diff options
author | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-01 11:31:55 -0800 |
---|---|---|
committer | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-01 11:31:55 -0800 |
commit | a0e97e71a49a8b54fddf8fb004b32f202f114011 (patch) | |
tree | 054113a630c57918635bace46ec58e80e7a08b54 /restconf-client | |
parent | 11510b43c277b8e1dd7e58d79785544810118c8e (diff) | |
parent | 8aafc0589b1c01af7828760c19254a2c2d1b0250 (diff) |
Merge branch 'master' of /home/jwagantall/linuxfoundation/onap/IT-21112/sli-plugins
Signed-off-by: Jessica Wagantall <jwagantall@linuxfoundation.org>
Diffstat (limited to 'restconf-client')
80 files changed, 12639 insertions, 0 deletions
diff --git a/restconf-client/.gitignore b/restconf-client/.gitignore new file mode 100755 index 000000000..b73caf31e --- /dev/null +++ b/restconf-client/.gitignore @@ -0,0 +1,34 @@ +#####standard .git ignore entries##### + +## IDE Specific Files ## +org.eclipse.core.resources.prefs +.classpath +.project +.settings +.idea +.externalToolBuilders +maven-eclipse.xml +workspace + +## Compilation Files ## +*.class +**/target +target +target-ide +MANIFEST.MF + +## Misc Ignores (OS specific etc) ## +bin/ +dist +*~ +*.ipr +*.iml +*.iws +classes +out/ +.DS_STORE +.metadata + +## Folders which contain auto generated source code ## +yang-gen-config +yang-gen-sal diff --git a/restconf-client/installer/pom.xml b/restconf-client/installer/pom.xml new file mode 100755 index 000000000..9114c7a22 --- /dev/null +++ b/restconf-client/installer/pom.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>2.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>restconf-client-installer</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-plugins :: restconf-client :: ${project.artifactId}</name> + + <properties> + <application.name>ccsdk-restconf-client</application.name> + <features.boot>${application.name}</features.boot> + <features.repositories>mvn:org.onap.ccsdk.sli.plugins/${features.boot}/${project.version}/xml/features + </features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + + <dependencies> + + <dependency> + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>restconf-client-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>maven-repo-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>stage/${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>true</appendAssemblyId> + </configuration> + </execution> + <execution> + <id>installer-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>${application.name}-${project.version}-installer</finalName> + <descriptors> + <descriptor>src/assembly/assemble_installer_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <transitive>false</transitive> + <outputDirectory>${project.build.directory}/assembly/system</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>true</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <includeGroupIds>org.onap.ccsdk.sli.plugins</includeGroupIds> + <scope>provided</scope> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>copy-version</id> + <goals> + <goal>copy-resources</goal> + </goals><!-- here the phase you need --> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/stage</outputDirectory> + <resources> + <resource> + <directory>src/main/resources/scripts</directory> + <includes> + <include>install-feature.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + + </executions> + </plugin> + + </plugins> + </build> +</project> diff --git a/restconf-client/installer/src/assembly/assemble_installer_zip.xml b/restconf-client/installer/src/assembly/assemble_installer_zip.xml new file mode 100644 index 000000000..8ffcb88a1 --- /dev/null +++ b/restconf-client/installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,58 @@ +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>installer_zip</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>755</fileMode> + <includes> + <include>*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>644</fileMode> + <excludes> + <exclude>*.sh</exclude> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/restconf-client/installer/src/assembly/assemble_mvnrepo_zip.xml b/restconf-client/installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100644 index 000000000..252c39d3c --- /dev/null +++ b/restconf-client/installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,48 @@ +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>repo</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/restconf-client/installer/src/main/resources/scripts/install-feature.sh b/restconf-client/installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 000000000..8e9195d57 --- /dev/null +++ b/restconf-client/installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +### +# ============LICENSE_START======================================================= +# ONAP : CCSDK +# ================================================================================ +# Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +ODL_HOME=${ODL_HOME:-/opt/opendaylight/current} +ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client} +INSTALLERDIR=$(dirname $0) + +REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}.zip + +if [ -f ${REPOZIP} ] +then + unzip -nd ${ODL_HOME} ${REPOZIP} +else + echo "ERROR : repo zip ($REPOZIP) not found" + exit 1 +fi + +${ODL_KARAF_CLIENT} feature:repo-add ${features.repositories} +${ODL_KARAF_CLIENT} feature:install ${features.boot} diff --git a/restconf-client/pom.xml b/restconf-client/pom.xml new file mode 100755 index 000000000..ee2d0423c --- /dev/null +++ b/restconf-client/pom.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>2.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>restconf-client</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-plugins :: restconf-client</name> + <description>This is an implementation of DG Execute Node that makes a call to an external RESTCONF API</description> + + <modules> + <module>provider</module> + <module>installer</module> + </modules> +</project> diff --git a/restconf-client/provider/pom.xml b/restconf-client/provider/pom.xml new file mode 100755 index 000000000..ab57af017 --- /dev/null +++ b/restconf-client/provider/pom.xml @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>2.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>restconf-client-provider</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>ccsdk-sli-plugins :: restconf-client :: ${project.artifactId}</name> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-core-artifacts</artifactId> + <version>${ccsdk.sli.core.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-sse</artifactId> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-common</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-provider</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>properties-node-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-data-impl</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>org.dom4j</groupId> + <artifactId>dom4j</artifactId> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>restapi-call-node-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>restconf-nb-rfc8040</artifactId> + <scope>provided</scope> + <exclusions> + <exclusion> + <groupId>javax.xml</groupId> + <artifactId>jsr173</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-parser-impl</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + + <!-- For test --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-servlet</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-grizzly2-http</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-test-util</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java new file mode 100644 index 000000000..620df282f --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiCallNode.java @@ -0,0 +1,484 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfapicall; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonWriter; + +import javax.ws.rs.core.UriBuilder; +import java.io.StringWriter; +import java.io.Writer; +import java.net.SocketException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.plugins.restapicall.Format; +import org.onap.ccsdk.sli.plugins.restapicall.HttpResponse; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restapicall.XmlParser; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializer; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatSerializerContext; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerFactory; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.Listener; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.MdsalSerializerHelper; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.SerializerHelper; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeSerializer; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeSerializer; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Strings.repeat; +import static java.lang.String.format; +import static java.lang.String.valueOf; +import static org.apache.commons.lang3.StringUtils.join; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.DELETE; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.GET; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PATCH; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PUT; +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.ATTEMPTS_MSG; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COLON; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMMA; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.COMM_FAIL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HEADER; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_REQ; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.HTTP_RES; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.MAX_RETRY_ERR; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.NO_MORE_RETRY; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REQ_ERR; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.REST_API_URL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_CODE; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_MSG; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RES_PRE; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_COUNT; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.RETRY_FAIL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.UPDATED_URL; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getSchemaCtxFromDir; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getUpdatedXmlReq; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.getYangParameters; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.parseUrl; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfListenerFactory.instance; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.UTF_HEADER; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_TREE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlWriter; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getModuleNamespace; +import static org.osgi.framework.FrameworkUtil.getBundle; + +/** + * Representation of a plugin to enable RESTCONF based CRUD operations from DG. + */ +public class RestconfApiCallNode implements SvcLogicJavaPlugin { + + /** + * Logger for the restconf api call node class. + */ + private static final Logger log = LoggerFactory.getLogger( + RestconfApiCallNode.class); + + /** + * Rest api call node service instance + */ + private RestapiCallNode restapiCallNode; + + /** + * Creates an instance of restconf api call node with restapi call node. + * + * @param r restapi call node + */ + public RestconfApiCallNode(RestapiCallNode r) { + this.restapiCallNode = r; + } + + /** + * Returns the restapi call node instance. + * @return + */ + public RestapiCallNode getRestapiCallNode() { + return restapiCallNode; + } + + /** + * Sends the restconf request using the parameters map and the memory + * context. And this method allows the directed graphs to interact with + * the restconf api call node + * + * @param paramMap parameters map + * @param ctx service logic context + * @throws SvcLogicException when svc logic exception occurs + */ + public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx) + throws SvcLogicException { + sendRequest(paramMap, ctx, 0); + } + + /** + * Sends the restconf request using the parameters map and the memory + * context along with the retry count. + * + * @param paramMap parameters map + * @param ctx service logic context + * @param retryCount number of retry counts + * @throws SvcLogicException when svc logic exception occurs + */ + public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx, + Integer retryCount) throws SvcLogicException { + RestapiCallNode rest = getRestapiCallNode(); + HttpResponse r = new HttpResponse(); + try { + YangParameters p = getYangParameters(paramMap); + + String pp = p.responsePrefix != null ? p.responsePrefix + '.' : ""; + Map<String, String> props = new HashMap<>((Map)ctx.toProperties()); + String uri = parseUrl(p.restapiUrl, p.httpMethod); + InstanceIdentifierContext<?> insIdCtx = getInsIdCtx(p, uri); + + String req = null; + if (p.httpMethod != GET && p.httpMethod != DELETE) { + req = serializeRequest(props, p, uri, insIdCtx); + if (p.httpMethod == PUT || p.httpMethod == PATCH) { + updateReq(req, p, insIdCtx); + } + } + if (req == null && p.requestBody != null) { + req = p.requestBody; + } + + r = rest.sendHttpRequest(req, p); + if (p.returnRequestPayload && req != null) { + ctx.setAttribute(pp + HTTP_REQ, req); + } + + String response = getResponse(ctx, p, pp, r); + if (response != null) { + try { + Map<String, String> resProp = serializeResponse( + p, uri, response, insIdCtx); + for (Map.Entry<String, String> pro : resProp.entrySet()) { + ctx.setAttribute(pro.getKey(), pro.getValue()); + } + } catch (SvcLogicException e) { + convertToNormalRes(ctx, p, pp, response); + } + } + } catch (SvcLogicException e) { + boolean shouldRetry = false; + if (e.getCause().getCause() instanceof SocketException) { + shouldRetry = true; + } + + log.error(REQ_ERR + e.getMessage(), e); + String prefix = parseParam(paramMap, RES_PRE, false, null); + setFailureResponseStatus(ctx, prefix, e.getMessage()); + } + + if (r != null && r.code >= 300) { + throw new SvcLogicException(valueOf(r.code) + + COLON + " " + r.message); + } + } + + private void convertToNormalRes(SvcLogicContext ctx , + YangParameters p, String pp, String body) + throws SvcLogicException { + if (p.convertResponse) { + Map<String, String> mm = null; + if (p.format == Format.XML) { + mm = XmlParser.convertToProperties(body, p.listNameList); + } else if (p.format == Format.JSON) { + mm = org.onap.ccsdk.sli.plugins.restapicall.JsonParser + .convertToProperties(body); + } + + if (mm != null) { + for (Map.Entry<String, String> entry : mm.entrySet()) { + ctx.setAttribute(pp + entry.getKey(), + entry.getValue()); + } + } + } + } + + /** + * Serializes the request message to JSON or XML from the properties. + * + * @param properties properties + * @param params YANG parameters + * @param uri URI + * @param insIdCtx instance identifier context + * @return JSON or XML message to be sent + * @throws SvcLogicException when serializing the request fails + */ + public String serializeRequest(Map<String, String> properties, + YangParameters params, String uri, + InstanceIdentifierContext insIdCtx) + throws SvcLogicException { + PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + DataFormatSerializerContext serCtx = new DataFormatSerializerContext( + null, uri, null, propSer); + DataFormatSerializer ser = DfSerializerFactory.instance() + .getSerializer(serCtx, params); + //TODO: Handling of XML annotations + return ser.encode(properties, null); + } + + /** + * Serializes the response message from JSON or XML to the properties. + * + * @param params YANG parameters + * @param uri URI + * @param response response message + * @param insIdCtx instance identifier context + * @return response message as properties + * @throws SvcLogicException when serializing the response fails + */ + public Map<String, String> serializeResponse(YangParameters params, + String uri, String response, + InstanceIdentifierContext insIdCtx) + throws SvcLogicException { + PropertiesNodeSerializer propSer = new MdsalPropertiesNodeSerializer( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + SerializerHelper helper = new MdsalSerializerHelper( + insIdCtx.getSchemaNode(), insIdCtx.getSchemaContext(), uri); + Listener listener = instance().getListener(helper, params); + DataFormatSerializerContext serCtx = new DataFormatSerializerContext( + listener, uri, null, propSer); + DataFormatSerializer ser = DfSerializerFactory.instance() + .getSerializer(serCtx, params); + return ser.decode(response); + } + + /** + * Returns instance identifier context for a uri using the schema context. + * + * @param params YANG parameters + * @param uri URI + * @return instance identifier context + * @throws SvcLogicException when getting schema context fails + */ + private InstanceIdentifierContext<?> getInsIdCtx(YangParameters params, + String uri) + throws SvcLogicException { + SchemaContext context = getSchemaContext(params); + return ParserIdentifier.toInstanceIdentifier(uri, context, null); + } + + /** + * Returns the global schema context or schema context of particular YANG + * files present in a directory path. + * + * @param params YANG parameters + * @return schema context + * @throws SvcLogicException when schema context fetching fails + */ + private SchemaContext getSchemaContext(YangParameters params) + throws SvcLogicException { + if (params.dirPath != null) { + return getSchemaCtxFromDir(params.dirPath); + } + BundleContext bc = getBundle(SchemaContext.class).getBundleContext(); + SchemaContext schemaContext = null; + if (bc != null) { + ServiceReference reference = bc.getServiceReference( + SchemaContext.class); + if (reference != null) { + schemaContext = (SchemaContext) bc.getService(reference); + } + } + return schemaContext; + } + + /** + * Returns the response message body of a http response message. + * + * @param ctx svc logic context + * @param params parameters + * @param pre prefix to be appended + * @param res http response + * @return response message body + */ + public String getResponse(SvcLogicContext ctx, YangParameters params, + String pre, HttpResponse res) { + ctx.setAttribute(pre + RES_CODE, valueOf(res.code)); + ctx.setAttribute(pre + RES_MSG, res.message); + + if (params.dumpHeaders && res.headers != null) { + for (Map.Entry<String, List<String>> a : res.headers.entrySet()) { + ctx.setAttribute(pre + HEADER + a.getKey(), + join(a.getValue(), COMMA)); + } + } + + if (res.body != null && res.body.trim().length() > 0) { + ctx.setAttribute(pre + HTTP_RES, res.body); + return res.body; + } + return null; + } + + /** + * Sets the failure response status in the context memory. + * + * @param ctx service logic context + * @param prefix prefix to be added + * @param errMsg error message + */ + private void setFailureResponseStatus(SvcLogicContext ctx, String prefix, + String errMsg) { + HttpResponse res = new HttpResponse(); + res.code = 500; + res.message = errMsg; + ctx.setAttribute(prefix + RES_CODE, valueOf(res.code)); + ctx.setAttribute(prefix + RES_MSG, res.message); + } + + /** + * Updates request message for JSON and XML data format, when the HTTP + * method points it as PUT or PATCH. + * + * @param req current request message + * @param p YANG parameters + * @param insIdCtx instance identifier context + * @return update request message + * @throws SvcLogicException when the data format type is wrong + */ + public String updateReq(String req, YangParameters p, + InstanceIdentifierContext<?> insIdCtx) + throws SvcLogicException { + + SchemaNode schemaNode = insIdCtx.getSchemaNode(); + Namespace modNs = getModuleNamespace(schemaNode.getQName(), + insIdCtx.getSchemaContext()); + String nodeName = schemaNode.getQName().getLocalName(); + + switch (p.format) { + case JSON: + return getUpdatedJsonReq(req, nodeName, modNs.moduleName()); + + case XML: + return getXmlReqForPutOp(req, nodeName, modNs.moduleNs()); + + default: + throw new SvcLogicException(format(FORMAT_ERR, p.format)); + } + } + + /** + * Returns the updated JSON request message, when the HTTP method + * points to PUT or PATCH. + * + * @param req current JSON request message + * @param nodeName root node name + * @param modName module name of the root node + * @return update JSON request message + */ + private String getUpdatedJsonReq(String req, String nodeName, + String modName) { + Writer writer = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(repeat(" ", 4)); + + JsonParser jsonParser = new JsonParser(); + JsonObject oldJson = (JsonObject)jsonParser.parse(req); + oldJson = remChildModName(oldJson, modName); + JsonObject newJson = new JsonObject(); + newJson.add(modName + COLON + nodeName, oldJson.deepCopy()); + + Gson gson= new Gson(); + gson.toJson(newJson, jsonWriter); + return writer.toString(); + } + + /** + * Removes module name from all the updated first level child node, if it + * is same as the root node added. + * + * @param oldJson JSON object for old request + * @param modName module name of root node + * @return JSON object for old request with updated child module name + */ + private JsonObject remChildModName(JsonObject oldJson, String modName) { + Iterator<Map.Entry<String, JsonElement>> it = oldJson.entrySet().iterator(); + Map<String, JsonElement> m = new HashMap<>(); + while (it.hasNext()) { + Map.Entry<String, JsonElement> jNode = it.next(); + if (jNode.getKey().contains(COLON)) { + String[] modArr = jNode.getKey().split(COLON); + if (modArr[0].equals(modName)) { + it.remove(); + m.put(modArr[1], jNode.getValue()); + } + } + } + if (!m.isEmpty()) { + for (Map.Entry<String, JsonElement> element : m.entrySet()) { + oldJson.add(element.getKey(), element.getValue()); + } + } + return oldJson; + } + + /** + * Returns the updated XML request message, when the HTTP method points + * to PUT or PATCH. + * + * @param req current JSON request message + * @param nodeName root node name + * @param modNs module namespace of the root node + * @return update JSON request message + * @throws SvcLogicException when XML parsing fails + */ + private String getXmlReqForPutOp(String req, String nodeName, + URI modNs) throws SvcLogicException { + req = getUpdatedXmlReq(req, nodeName, modNs.toString()); + Document oldDoc; + try { + oldDoc = DocumentHelper.parseText(req); + } catch (DocumentException e) { + throw new SvcLogicException(XML_TREE_ERR, e); + } + Writer writer = getXmlWriter( + UTF_HEADER + oldDoc.getRootElement().asXML(), "4"); + return writer.toString(); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java new file mode 100644 index 000000000..1309102b3 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfapicall/RestconfApiUtils.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfapicall; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.HttpMethod; +import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; +import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; + +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.getParameters; +import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam; +import static org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode.DEFAULT_MODE; +import static org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource.forFile; +import static org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors.defaultReactor; +import static org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangStatementStreamSource.create; + +/** + * Utilities for restconf api call node. + */ +public final class RestconfApiUtils { + + static final String RES_CODE = "response-code"; + + static final String HTTP_REQ ="httpRequest"; + + static final String RES_PRE = "responsePrefix"; + + static final String RES_MSG = "response-message"; + + static final String HEADER = "header."; + + static final String COMMA = ","; + + static final String COLON = ":"; + + static final String HTTP_RES = "httpResponse"; + + static final String REST_API_URL = "restapiUrl"; + + static final String UPDATED_URL = "URL was set to"; + + static final String COMM_FAIL = "Failed to communicate with host %s." + + "Request will be re-attempted using the host %s."; + + static final String RETRY_COUNT = "This is retry attempt %d out of %d"; + + static final String RETRY_FAIL = "Retry attempt has failed. No further " + + "retry shall be attempted, calling setFailureResponseStatus"; + + static final String NO_MORE_RETRY = "Could not attempt retry"; + + static final String MAX_RETRY_ERR = "Maximum retries reached, calling " + + "setFailureResponseStatus"; + + static final String ATTEMPTS_MSG = "%d attempts were made out of %d " + + "maximum retries"; + + static final String REQ_ERR = "Error sending the request: "; + + private static final String SLASH = "/"; + + private static final String DIR_PATH = "dirPath"; + + private static final String URL_SYNTAX = "The following URL cannot be " + + "parsed into URI : "; + + private static final String YANG = ".yang"; + + private static final String YANG_FILE_ERR = "Unable to parse the YANG " + + "file provided"; + + //No instantiation. + private RestconfApiUtils() { + } + + /** + * Returns the YANG parameters after parsing it from the map. + * + * @param paramMap parameters map + * @return YANG parameters + * @throws SvcLogicException when parsing of parameters map fail + */ + static YangParameters getYangParameters(Map<String, String> paramMap) + throws SvcLogicException { + YangParameters param = (YangParameters) getParameters( + paramMap, new YangParameters()); + param.dirPath = parseParam(paramMap, DIR_PATH, false, null); + return param; + } + + /** + * Parses the restconf URL and gives the YANG path from it, which can be + * used to get schema node. If it is a PUT operation, then a node must be + * reduced from the url to make it always point to the parent. + * + * @param url restconf URL + * @param method HTTP operation + * @return YANG path pointing to parent + * @throws SvcLogicException when parsing the URL fails + */ + public static String parseUrl(String url, HttpMethod method) + throws SvcLogicException { + URI uri; + try { + uri = new URI(url); + } catch (URISyntaxException e) { + throw new SvcLogicException(URL_SYNTAX + url, e); + } + + String path = uri.getPath(); + path = getParsedPath(path); + return path; + } + + /** + * Returns the path which contains only the schema nodes. + * + * @param path path + * @return path representing schema + */ + private static String getParsedPath(String path) { + String firstHalf; + String secondHalf; + if (path.contains(COLON)) { + String[] p = path.split(COLON); + if (p[0].contains(SLASH)) { + int slash = p[0].lastIndexOf(SLASH); + firstHalf = p[0].substring(slash + 1); + } else { + firstHalf = p[0]; + } + secondHalf = path.substring(p[0].length() + 1); + return firstHalf + COLON + secondHalf; + } else if (path.contains(SLASH)) { + String[] p = path.split(SLASH); + if (p.length > 4) { + String actual = p[3] + COLON + p[4]; + if (p.length > 5) { + secondHalf = path.substring( + p[1].length() + p[2].length() + actual.length() + 3); + path = actual + secondHalf; + } else { + path = actual; + } + } + } + return path; + } + + /** + * Returns the schema context of the YANG files present in a directory. + * + * @param di directory path + * @return YANG schema context + * @throws SvcLogicException when YANG file reading fails + */ + static SchemaContext getSchemaCtxFromDir(String di) + throws SvcLogicException { + Path d = Paths.get(di); + File dir = d.toFile(); + List<File> yangFiles = new LinkedList<>(); + getYangFiles(dir, yangFiles); + final Collection<YangStatementStreamSource> sources = + new ArrayList<>(yangFiles.size()); + for (File file : yangFiles) { + try { + sources.add(create(forFile(file))); + } catch (IOException | YangSyntaxErrorException e) { + throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e); + } + } + + final CrossSourceStatementReactor.BuildAction reactor = defaultReactor() + .newBuild(DEFAULT_MODE).addSources(sources); + try { + return reactor.buildEffective(); + } catch (ReactorException e) { + throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e); + } + } + + /** + * Returns all the YANG files present in a directory recursively. + * + * @param dir path of the directory + * @param yangFiles list of YANG files + */ + private static void getYangFiles(File dir, List<File> yangFiles) { + if (dir.exists()) { + File[] files = dir.listFiles(); + if (files != null) { + processFiles(files, yangFiles); + } + } + } + + /** + * Processes all the obtained files by isolating all the YANG files from + * all the directory of the given path recursively. + * + * @param files files in the given path + * @param yangFiles YANG files list + */ + private static void processFiles(File[] files, List<File> yangFiles) { + for (File file : files) { + if (file.isFile() && file.getName().endsWith(YANG)) { + yangFiles.add(file); + } else if (file.isDirectory()) { + getYangFiles(file, yangFiles); + } + } + } + + /** + * Returns the updated XML request message by adding root node to it. + * + * @param req XML request + * @param nodeName root node name + * @param modNs module namespace of the root node + * @return updated XML request message + */ + static String getUpdatedXmlReq(String req, String nodeName, String modNs) { + String rootNode = "\n<" + nodeName + " xmlns=\"" + modNs + + "\">\n"; + req = req.replaceFirst("\n", rootNode); + req = req + "</" + nodeName + ">"; + return req.replaceAll(">\\s+<", "><"); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java new file mode 100644 index 000000000..3213cae15 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/AdditionalHeaderWebTarget.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; +import java.net.URI; +import java.util.Map; + +/** + * Adds additional headers for SSE request. + */ +class AdditionalHeaderWebTarget implements WebTarget { + private WebTarget base; + private String token; + + private String accessToken = "X-ACCESS-TOKEN"; + + public AdditionalHeaderWebTarget(WebTarget target, String token) { + base = target; + this.token = token; + } + + @Override + public Invocation.Builder request() { + return base.request().header(accessToken, token); + } + + @Override + public Invocation.Builder request(String... acceptedResponseTypes) { + return base.request().header(accessToken, token); + } + + @Override + public Invocation.Builder request(MediaType... acceptedResponseTypes) { + return base.request().header(accessToken, token); + } + + @Override + public Configuration getConfiguration() { + return base.getConfiguration(); + } + + @Override + public URI getUri() { + return base.getUri(); + } + + @Override + public UriBuilder getUriBuilder() { + return base.getUriBuilder(); + } + + @Override + public WebTarget path(String path) { + return base.path(path); + } + + @Override + public WebTarget resolveTemplate(String name, Object value) { + return base.resolveTemplate(name, value); + } + + @Override + public WebTarget resolveTemplate(String name, Object value, boolean encodeSlashInPath) { + return base.resolveTemplate(name, value, encodeSlashInPath); + } + + @Override + public WebTarget resolveTemplateFromEncoded(String name, Object value) { + return base.resolveTemplateFromEncoded(name, value); + } + + @Override + public WebTarget resolveTemplates(Map<String, Object> templateValues) { + return base.resolveTemplates(templateValues); + } + + @Override + public WebTarget resolveTemplates(Map<String, Object> templateValues, boolean encodeSlashInPath) { + return base.resolveTemplates(templateValues, encodeSlashInPath); + } + + @Override + public WebTarget resolveTemplatesFromEncoded(Map<String, Object> templateValues) { + return base.resolveTemplatesFromEncoded(templateValues); + } + + @Override + public WebTarget matrixParam(String name, Object... values) { + return base.matrixParam(name, values); + } + + @Override + public WebTarget queryParam(String name, Object... values) { + return base.queryParam(name, values); + } + + @Override + public WebTarget property(String name, Object value) { + return base.property(name, value); + } + + @Override + public WebTarget register(Class<?> componentClass) { + return base.register(componentClass); + } + + @Override + public WebTarget register(Class<?> componentClass, int priority) { + return base.register(componentClass, priority); + } + + @Override + public WebTarget register(Class<?> componentClass, Class<?>... contracts) { + return base.register(componentClass, contracts); + } + + @Override + public WebTarget register(Class<?> componentClass, Map<Class<?>, Integer> contracts) { + return base.register(componentClass, contracts); + } + + @Override + public WebTarget register(Object component) { + return base.register(component); + } + + @Override + public WebTarget register(Object component, int priority) { + return base.register(component, priority); + } + + @Override + public WebTarget register(Object component, Class<?>... contracts) { + return base.register(component, contracts); + } + + @Override + public WebTarget register(Object component, Map<Class<?>, Integer> contracts) { + return base.register(component, contracts); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java new file mode 100644 index 000000000..a76554d5a --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventHandler.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.jersey.media.sse.InboundEvent; +import org.glassfish.jersey.media.sse.EventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Listener that can be registered to listen for notifications. + */ +class EventHandler implements EventListener { + private static final Logger log = LoggerFactory.getLogger(EventListener.class); + private RestconfDiscoveryNode node; + + public EventHandler(RestconfDiscoveryNode node) { + this.node = node; + } + + @Override + public void onEvent(InboundEvent event) { + String payload = event.readData(); + if (!node.eventQueue().offer(payload)) { + log.error("Unable to process event {} as processing queue is full", payload); + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java new file mode 100644 index 000000000..4f28072d3 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/EventProcessor.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; + +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.restapicall.JsonParser.convertToProperties; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Processes the events from event queue and executes callback DG. + */ +class EventProcessor implements Runnable { + + private static final Logger log = getLogger(EventProcessor.class); + private RestconfDiscoveryNode node; + + private static final String EVENT_SUBSCRIPTION_ID = "notification." + + "push-change-update.subscription-id"; + + public EventProcessor(RestconfDiscoveryNode node) { + this.node = node; + } + + @Override + public void run() { + while(true) { + try { + String payload = node.eventQueue().take(); + Map<String, String> param = convertToProperties(payload); + String id = param.get(EVENT_SUBSCRIPTION_ID); + SubscriptionInfo info = node.subscriptionInfoMap().get(id); + if (info != null) { + SvcLogicContext ctx = setContext(param); + SvcLogicGraphInfo callbackDG = info.callBackDG(); + callbackDG.executeGraph(ctx); + } + } catch (InterruptedException | SvcLogicException e) { + log.error("Interrupted!", e); + Thread.currentThread().interrupt(); + } + } + } + + private SvcLogicContext setContext(Map<String, String> param) { + SvcLogicContext ctx = new SvcLogicContext(); + for (Map.Entry<String, String> entry : param.entrySet()) { + ctx.setAttribute(entry.getKey(), entry.getValue()); + } + return ctx; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java new file mode 100644 index 000000000..cf69d7a3c --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/RestconfDiscoveryNode.java @@ -0,0 +1,310 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.jersey.media.sse.EventSource; +import org.glassfish.jersey.media.sse.SseFeature; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.Parameters; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode; +import org.slf4j.Logger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Representation of a plugin to subscribe for notification and then + * to handle the received notifications. + */ +public class RestconfDiscoveryNode implements SvcLogicDiscoveryPlugin { + + private static final Logger log = getLogger(RestconfDiscoveryNode.class); + + private ExecutorService executor = Executors.newCachedThreadPool(); + private Map<String, PersistentConnection> runnableInfo = new ConcurrentHashMap<>(); + private RestconfApiCallNode restconfApiCallNode; + + private volatile Map<String, SubscriptionInfo> subscriptionInfoMap = new ConcurrentHashMap<>(); + private volatile LinkedBlockingQueue<String> eventQueue = new LinkedBlockingQueue<>(); + + private static final String SUBSCRIBER_ID = "subscriberId"; + private static final String RESPONSE_CODE = "response-code"; + private static final String RESPONSE_PREFIX = "responsePrefix"; + private static final String OUTPUT_IDENTIFIER = "ietf-subscribed-notif" + + "ications:establish-subscription.output.identifier"; + private static final String RESPONSE_CODE_200 = "200"; + private static final String SSE_URL = "sseConnectURL"; + + /** + * Creates an instance of RestconfDiscoveryNode and starts processing of + * event. + * + * @param r restconf api call node + */ + public RestconfDiscoveryNode(RestconfApiCallNode r) { + this.restconfApiCallNode = r; + ExecutorService e = Executors.newFixedThreadPool(20); + EventProcessor p = new EventProcessor(this); + for (int i = 0; i < 20; ++i) { + e.execute(p); + } + } + + @Override + public void establishSubscription(Map<String, String> paramMap, + SvcLogicContext ctx) throws SvcLogicException { + String subscriberId = paramMap.get(SUBSCRIBER_ID); + if (subscriberId == null) { + throw new SvcLogicException("Subscriber Id is null"); + } + + restconfApiCallNode.sendRequest(paramMap, ctx); + + if (getResponseCode(paramMap.get(RESPONSE_PREFIX), ctx).equals(RESPONSE_CODE_200)) { + // TODO: save subscription id and subscriber in MYSQL + + establishPersistentConnection(paramMap, ctx, subscriberId); + } else { + log.info("Failed to subscribe {}", subscriberId); + throw new SvcLogicException(ctx.getAttribute(RESPONSE_CODE)); + } + } + + @Override + public void modifySubscription(Map<String, String> paramMap, SvcLogicContext ctx) { + // TODO: to be implemented + } + + @Override + public void deleteSubscription(Map<String, String> paramMap, SvcLogicContext ctx) { + String id = getSubscriptionId(paramMap.get(SUBSCRIBER_ID)); + if (id != null) { + PersistentConnection conn = runnableInfo.get(id); + conn.terminate(); + runnableInfo.remove(id); + subscriptionInfoMap.remove(id); + } + } + + class PersistentConnection implements Runnable { + private String url; + private volatile boolean running = true; + private Map<String, String> paramMap; + + PersistentConnection(String url, Map<String, String> paramMap) { + this.url = url; + this.paramMap = paramMap; + } + + private void terminate() { + running = false; + } + + @Override + public void run() { + Parameters p; + WebTarget target = null; + try { + RestapiCallNode restapi = restconfApiCallNode.getRestapiCallNode(); + p = RestapiCallNode.getParameters(paramMap, new Parameters()); + Client client = ignoreSslClient().register(SseFeature.class); + target = restapi.addAuthType(client, p).target(url); + } catch (SvcLogicException e) { + log.error("Exception occured!", e); + Thread.currentThread().interrupt(); + } + + target = addToken(target, paramMap.get("customHttpHeaders")); + EventSource eventSource = EventSource.target(target).build(); + eventSource.register(new EventHandler(RestconfDiscoveryNode.this)); + eventSource.open(); + log.info("Connected to SSE source"); + while (running) { + try { + log.info("SSE state " + eventSource.isOpen()); + Thread.sleep(5000); + } catch (InterruptedException e) { + log.error("Interrupted!", e); + Thread.currentThread().interrupt(); + } + } + eventSource.close(); + log.info("Closed connection to SSE source"); + } + + private Client ignoreSslClient() { + SSLContext sslcontext = null; + + try { + sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(null, new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } }, new java.security.SecureRandom()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new IllegalStateException(e); + } + + return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build(); + } + } + + protected String getTokenId(String customHttpHeaders) { + if (customHttpHeaders.contains("=")) { + String[] s = customHttpHeaders.split("="); + return s[1]; + } + return customHttpHeaders; + } + + protected WebTarget addToken(WebTarget target, String customHttpHeaders) { + if (customHttpHeaders == null) { + return target; + } + + return new AdditionalHeaderWebTarget( + target, getTokenId(customHttpHeaders)); + } + + /** + * Establishes a persistent between the client and server. + * + * @param paramMap input paramter map + * @param ctx service logic context + * @param subscriberId subscriber identifier + */ + void establishPersistentConnection(Map<String, String> paramMap, SvcLogicContext ctx, + String subscriberId) { + String id = getOutputIdentifier(paramMap.get(RESPONSE_PREFIX), ctx); + SvcLogicGraphInfo callbackDG = new SvcLogicGraphInfo(paramMap.get("module"), + paramMap.get("rpc"), + paramMap.get("version"), + paramMap.get("mode")); + SubscriptionInfo info = new SubscriptionInfo(); + info.callBackDG(callbackDG); + info.subscriptionId(id); + info.subscriberId(subscriberId); + subscriptionInfoMap.put(id, info); + + String url = paramMap.get(SSE_URL); + PersistentConnection connection = new PersistentConnection(url, paramMap); + runnableInfo.put(id, connection); + executor.execute(connection); + } + + /** + * Returns response code. + * + * @param prefix prefix given in input parameter + * @param ctx service logic context + * @return response code + */ + String getResponseCode(String prefix, SvcLogicContext ctx) { + return ctx.getAttribute(getPrefix(prefix) + RESPONSE_CODE); + } + + /** + * Returns subscription id from event. + * + * @param prefix prefix given in input parameter + * @param ctx service logic context + * @return subscription id from event + */ + String getOutputIdentifier(String prefix, SvcLogicContext ctx) { + return ctx.getAttribute(getPrefix(prefix) + OUTPUT_IDENTIFIER); + } + + private String getPrefix(String prefix) { + return prefix != null ? prefix + "." : ""; + } + + private String getSubscriptionId(String subscriberId) { + for (Map.Entry<String,SubscriptionInfo> entry + : subscriptionInfoMap.entrySet()) { + if (entry.getValue().subscriberId() + .equals(subscriberId)) { + return entry.getKey(); + } + } + return null; + } + + /** + * Returns restconfApiCallNode. + * + * @return restconfApiCallNode + */ + protected RestconfApiCallNode restconfapiCallNode() { + return restconfApiCallNode; + } + + /** + * Sets restconfApiCallNode. + * + * @param node restconfApiCallNode + */ + void restconfapiCallNode(RestconfApiCallNode node) { + restconfApiCallNode = node; + } + + Map<String, SubscriptionInfo> subscriptionInfoMap() { + return subscriptionInfoMap; + } + + void subscriptionInfoMap(Map<String, SubscriptionInfo> subscriptionInfoMap) { + this.subscriptionInfoMap = subscriptionInfoMap; + } + + LinkedBlockingQueue<String> eventQueue() { + return eventQueue; + } + + void eventQueue(LinkedBlockingQueue<String> eventQueue) { + this.eventQueue = eventQueue; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java new file mode 100644 index 000000000..4ed3660ca --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SubscriptionInfo.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +/** + * Holder to store information of subscription. + */ +public class SubscriptionInfo { + private String subscriptionId; + private String subscriberId; + private SvcLogicGraphInfo callbackDG; + private String yangFilePath; + private String filterUrl; + + /** + * Returns callback DG. + * + * @return callback DG + */ + public SvcLogicGraphInfo callBackDG() { + return callbackDG; + } + + /** + * Sets callback DG. + * + * @param callbackDg callback DG + */ + public void callBackDG(SvcLogicGraphInfo callbackDg) { + this.callbackDG = callbackDg; + } + + /** + * Returns YANG file path. + * + * @return YANG file path + */ + public String yangFilePath() { + return yangFilePath; + } + + /** + * Sets YANG file path. + * + * @param yangFilePath yang file path + */ + public void yangFilePath(String yangFilePath) { + this.yangFilePath = yangFilePath; + } + + /** + * Returns filter URL. + * + * @return filter URL + */ + public String filterUrl() { + return filterUrl; + } + + /** + * Sets filter URL. + * + * @param filterUrl filter URL + */ + public void filterUrl(String filterUrl) { + this.filterUrl = filterUrl; + } + + /** + * Returns subscription Id. + * + * @return subscription Id + */ + public String subscriptionId() { + return subscriptionId; + } + + /** + * Sets subscription id. + * + * @param subscriptionId subscription id + */ + public void subscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + } + + /** + * Returns subscription Id. + * + * @return subscription Id + */ + public String subscriberId() { + return subscriberId; + } + + /** + * Sets subscriber id. + * + * @param subscriberId subscriber id + */ + public void subscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java new file mode 100644 index 000000000..dfe8cd5b7 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicDiscoveryPlugin.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import java.util.Map; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; + +/** + * Abstraction of a plugin to enable discovery from DG. + */ +public interface SvcLogicDiscoveryPlugin extends SvcLogicJavaPlugin { + + /** + * Allows directed graphs to establish a discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>templateDirName</td><td>Optional</td><td>full path to YANG directory that can be used to build a request</td><td>/sdncopt/bvc/resconfapi/test</td></tr> + * <tr><td>establishSubscriptionURL</td><td>Mandatory</td><td>url to establish connection with server</td><td>https://127.0.0.1:8181/restconf/operations/ietf-subscribed-notifications:establish-subscription</td></tr> + * <tr><td>sseConnectURL</td><td>Mandatory</td><td>url to setup SSE connection with server</td><td>https://127.0.0.1:8181/restconf/streams/yang-push-json</td></tr> + * <tr><td>callbackDG</td><td>Mandatory</td><td>callback DG to process the received notification</td><td>Resource-Discovery:handleSOTNTopology</td></tr> + * <tr><td>filterURL</td><td>Optional</td><td>url which needs to be subscribed, if null subscribe to all</td><td>http://example.com/sample-data/1.0</td></tr> + * <tr><td>subscriptionType</td><td>Optional</td><td>type of subscription, periodic or onDataChange</td><td>onDataChange</td></tr> + * <tr><td>updateFrequency</td><td>Optional</td><td>update frequency in milli seconds when subscription type is periodic</td><td>1000</td></tr> + * <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr> + * <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr> + * <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr> + * <tr><td>responsePrefix</td><td>Optional</td><td>location the notification response will be written to in context memory</td><td>tmp.restconfdiscovery.result</td></tr> + * <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr> + * <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr> + * <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + * @since 11.0.2 + * @see String#split(String, int) + */ + void establishSubscription(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException; + + /** + * Allows directed graphs to modify a discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>subscriberId</td><td>Mandatory</td><td>subscription subscriber's identifier</td><td>topologyId/1111</td></tr> + * <tr><td>templateDirName</td><td>Optional</td><td>full path to YANG directory that can be used to build a request</td><td>/sdncopt/bvc/resconfapi/test</td></tr> + * <tr><td>establishSubscriptionURL</td><td>Mandatory</td><td>url to establish connection with server</td><td>https://127.0.0.1:8181/restconf/operations/ietf-subscribed-notifications:establish-subscription</td></tr> + * <tr><td>sseConnectURL</td><td>Mandatory</td><td>url to setup SSE connection with server</td><td>https://127.0.0.1:8181/restconf/streams/yang-push-json</td></tr> + * <tr><td>callbackDG</td><td>Mandatory</td><td>callback DG to process the received notification</td><td>Resource-Discovery:handleSOTNTopology</td></tr> + * <tr><td>filterURL</td><td>Optional</td><td>url filter list which needs to be subscribed, if null subscribe to all</td><td>http://example.com/sample-data/1.0</td></tr> + * <tr><td>subscriptionType</td><td>Optional</td><td>type of subscription, periodic or onDataChange</td><td>onDataChange</td></tr> + * <tr><td>updateFrequency</td><td>Optional</td><td>update frequency in milli seconds when subscription type is periodic</td><td>1000</td></tr> + * <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr> + * <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr> + * <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr> + * <tr><td>responsePrefix</td><td>Optional</td><td>location the notification response will be written to in context memory</td><td>tmp.restconfdiscovery.result</td></tr> + * <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr> + * <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr> + * <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + * @since 11.0.2 + * @see String#split(String, int) + */ + void modifySubscription(Map<String, String> paramMap, SvcLogicContext ctx); + + /** + * Allows directed graphs to delete the discovery subscription for a given subscriber. + * @param paramMap HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>subscriberId</td><td>Mandatory</td><td>subscription subscriber's identifier</td><td>topologyId/1111</td></tr> + * </tbody> + * </table> + * @param ctx Reference to context memory + * @throws SvcLogicException + */ + void deleteSubscription(Map<String, String> paramMap, SvcLogicContext ctx); + +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java new file mode 100644 index 000000000..1cc6261ab --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SvcLogicGraphInfo.java @@ -0,0 +1,178 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicGraph; +import org.onap.ccsdk.sli.core.sli.SvcLogicStore; +import org.onap.ccsdk.sli.core.sli.provider.SvcLogicService; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +/** + * Holder to store callback directed graph info. + */ +class SvcLogicGraphInfo { + private String module; + private String rpc; + private String mode; + private String version; + + /** + * Creates an instance of SvcLogicGraphInfo. + * + * @param module module name of callback DG + * @param rpc rpc name of callback DG + * @param mode mode of callback DG + * @param version version of callback DG + */ + public SvcLogicGraphInfo(String module, String rpc, String mode, String version) { + this.module = module; + this.rpc = rpc; + this.mode = mode; + this.version = version; + } + + public SvcLogicGraphInfo() {} + + /** + * Returns module name of callback DG. + * + * @return module name of callback DG + */ + public String module() { + return module; + } + + /** + * Sets module of callback DG. + * + * @param module module name of the DG + */ + public void module(String module) { + this.module = module; + } + + /** + * Returns rpc of callback DG. + * + * @return rpc of callback DG + */ + public String rpc() { + return rpc; + } + + /** + * Sets rpc of callback DG. + * + * @param rpc rpc attribute of the DG + */ + public void rpc(String rpc) { + this.rpc = rpc; + } + + /** + * Returns mode of callback DG. + * + * @return mode of callback DG + */ + public String mode() { + return mode; + } + + /** + * Sets mode of DG. + * + * @param mode mode of the DG + */ + public void mode(String mode) { + this.mode = mode; + } + + /** + * Returns version of callback DG. + * + * @return version of callback DG + */ + public String version() { + return version; + } + + /** + * Sets version of DG. + * + * @param version version of the DG + */ + public void version(String version) { + this.version = version; + } + + /** + * Executes call back DG. + * + * @param ctx service logic context + * @throws SvcLogicException service logic error + */ + public void executeGraph(SvcLogicContext ctx) throws SvcLogicException { + SvcLogicService service = findSvcLogicService(); + if (service == null) { + throw new SvcLogicException("\"Could not get SvcLogicService reference\""); + } + + SvcLogicStore store = service.getStore(); + if (store != null) { + SvcLogicGraph subGraph = store.fetch(module, rpc, mode, version); + if (subGraph != null) { + ctx.setAttribute("subGraph", subGraph.toString()); + service.execute(subGraph, ctx); + } else { + throw new SvcLogicException("Failed to call child [" + module + + "," + rpc + "," + version + + "," + mode + "] because" + + " the" + " graph could" + + " not be found"); + } + } else { + throw new SvcLogicException("\"Could not get SvcLogicStore reference\""); + } + } + + private static SvcLogicService findSvcLogicService() throws SvcLogicException { + Bundle bundle = FrameworkUtil.getBundle(SvcLogicService.class); + if (bundle == null) { + throw new SvcLogicException("Cannot find bundle reference for " + + SvcLogicService.NAME); + } + + BundleContext bctx = bundle.getBundleContext(); + ServiceReference<SvcLogicService> sref = bctx.getServiceReference( + SvcLogicService.class); + if (sref != null) { + return bctx.getService(sref); + } else { + throw new SvcLogicException("Cannot find service reference for " + + SvcLogicService.NAME); + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java new file mode 100644 index 000000000..185f70ba0 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Annotation.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Representation of an entity that represents annotated attribute. + */ +public class Annotation { + + /** + * Name of the annotation. + */ + private String name; + + /** + * Value of the annotation. + */ + private String value; + + /** + * Creates an instance of annotation. + * + * @param n annotation name + * @param v annotation value + */ + public Annotation(String n, String v) { + name = n; + value = v; + } + + /** + * Returns name of annotation. + * + * @return name of annotation + */ + public String name() { + return name; + } + + /** + * Returns value of annotation. + * + * @return value of annotation + */ + public String value() { + return value; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java new file mode 100644 index 000000000..c692f1dd2 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormat.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Representation of data format. + */ +public enum DataFormat { + + /** + * XML data format. + */ + XML, + + /** + * JSON data format. + */ + JSON +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java new file mode 100644 index 000000000..cab64391a --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializer.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.List; +import java.util.Map; + +/** + * Abstraction of serializer to encode/decode context memory parameters + * to/from specified data format. + */ +public abstract class DataFormatSerializer { + + /** + * Data format type of the serializer. + */ + private DataFormat dataFormat; + + /** + * Data format serializer context. + */ + private DataFormatSerializerContext serializerContext; + + /** + * Creates an instance of data format serializer. + * + * @param d type of data format + * @param s data format serializer context + */ + protected DataFormatSerializer(DataFormat d, + DataFormatSerializerContext s) { + this.dataFormat = d; + this.serializerContext = s; + } + + /** + * Encodes context memory parameters to data format. + * + * @param param context memory parameter + * @param annotations annotations + * @return data format body + * @throws SvcLogicException when serialization fails + */ + public abstract String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) throws SvcLogicException; + + /** + * Decodes data format body to context memory parameters. + * + * @param dataFormatBody abstract node + * @return context memory parameters + * @throws SvcLogicException when serialization fails + */ + public abstract Map<String, String> decode(String dataFormatBody) + throws SvcLogicException; + + /** + * Returns data format serializer context. + * + * @return data format serializer context + */ + public DataFormatSerializerContext serializerContext() { + return serializerContext; + } + + /** + * Returns supported data format. + * + * @return supported data format + */ + public DataFormat dataFormat() { + return dataFormat; + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java new file mode 100644 index 000000000..919e82af3 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerContext.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeSerializer; + +import java.util.Map; + +/** + * Abstraction of data format serializer context. + */ +public class DataFormatSerializerContext { + + /** + * Data format listener. + */ + private Listener listener; + + /** + * URI corresponding to the instance identifier. + */ + private String uri; + + /** + * Protocol annotation. + */ + private Map<String, String> protocolAnnotation; + + /** + * Properties node serializer. + */ + private PropertiesNodeSerializer propNodeSerializer; + + /** + * Creates an instance of data format serializer context. + * + * @param l data format listener + * @param u URI corresponding to instance identifier + * @param p protocol annotations + * @param s properties node serializer + */ + public DataFormatSerializerContext(Listener l, String u, + Map<String, String> p, + PropertiesNodeSerializer s) { + listener = l; + uri = u; + protocolAnnotation = p; + propNodeSerializer = s; + } + + /** + * Returns the data format listener. + * + * @return data format listener + */ + public Listener listener() { + return listener; + } + + /** + * Returns the URI. + * + * @return URI + */ + public String uri() { + return uri; + } + + /** + * Returns the protocol annotations. + * + * @return protocol annotations + */ + public Map<String, String> getProtocolAnnotation() { + return protocolAnnotation; + } + + /** + * Returns the properties node serializer. + * + * @return properties node serializer + */ + public PropertiesNodeSerializer getPropNodeSerializer() { + return propNodeSerializer; + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java new file mode 100644 index 000000000..45317522a --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonListener.java @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + + +/** + * Representation of default implementation of JSON listener. + */ +public class DefaultJsonListener implements JsonListener { + + /** + * Serializer helper to convert to properties node. + */ + private SerializerHelper serializerHelper; + + /** + * Name of the current JSON node. + */ + private String name; + + /** + * Module name of the current JSON node. + */ + private String modName; + + /** + * Value of the current JSON node. + */ + private String value; + + /** + * Value namespace of the current JSON node. + */ + private String valueNs; + + /** + * Creates an instance of default json listener with its serializer helper. + * + * @param serializerHelper serializer helper + */ + public DefaultJsonListener(SerializerHelper serializerHelper) { + this.serializerHelper = serializerHelper; + } + + @Override + public void enterJsonNode(String nodeName, JsonNode node, + NodeType nodeType) throws SvcLogicException { + getNodeName(nodeName, false); + + switch (nodeType) { + case SINGLE_INSTANCE_LEAF_NODE: + getNodeName(node.asText(), true); + serializerHelper.addNode(name, modName, value, valueNs, + SINGLE_INSTANCE_LEAF_NODE); + break; + + case MULTI_INSTANCE_LEAF_NODE: + getNodeName(node.asText(), true); + serializerHelper.addNode(name, modName, value, valueNs, + MULTI_INSTANCE_LEAF_NODE); + break; + + case SINGLE_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + SINGLE_INSTANCE_NODE); + break; + + case MULTI_INSTANCE_NODE: + serializerHelper.addNode(name, modName, null, null, + MULTI_INSTANCE_NODE); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } + } + + @Override + public void exitJsonNode(JsonNode node) throws SvcLogicException { + serializerHelper.exitNode(); + } + + @Override + public SerializerHelper serializerHelper() { + return serializerHelper; + } + + /** + * Parses the abstract JSON name and fills the node name and node + * namespace or value and value namespace of the current JSON node . + * + * @param abstractName full name value + * @param isVal if it is for value parsing + */ + private void getNodeName(String abstractName, boolean isVal) { + String[] val = abstractName.split(":"); + if (val.length == 2) { + if (isVal) { + valueNs = val[0]; + value = val[1]; + } else { + modName = val[0]; + name = val[1]; + } + } else { + if (isVal) { + value = val[0]; + valueNs = null; + } else { + name = val[0]; + modName = null; + } + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java new file mode 100644 index 000000000..47cb8b292 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultJsonWalker.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +import java.util.Iterator; +import java.util.Map; + +import static com.fasterxml.jackson.databind.node.JsonNodeType.NUMBER; +import static com.fasterxml.jackson.databind.node.JsonNodeType.STRING; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + +/** + * Implementation of JSON walker to walk through the nodes and process it. + */ +public class DefaultJsonWalker implements JsonWalker { + + @Override + public void walk(JsonListener listener, JsonNode jsonNode) throws + SvcLogicException { + Iterator<Map.Entry<String, JsonNode>> children = jsonNode.fields(); + while (children.hasNext()) { + Map.Entry<String, JsonNode> child = children.next(); + JsonNode value = child.getValue(); + String key = child.getKey(); + if (value.isArray()) { + processMultiNodes(key, value, listener); + } else { + processSingleNode(key, value, listener); + } + } + } + + /** + * Processes single instance node or leaf, by adding the node to from + * JSON and walking through all its children recursively. + * + * @param key JSON name + * @param value JSON node + * @param listener JSON listener + * @throws SvcLogicException when processing the node fails + */ + private void processSingleNode(String key, JsonNode value, + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + if (!value.isContainerNode()) { + nodeType = SINGLE_INSTANCE_LEAF_NODE; + } else { + nodeType = SINGLE_INSTANCE_NODE; + } + processNode(key, value, nodeType, listener); + } + + /** + * Processes multi instance node or leaf, by adding the node to from JSON + * and walking through all its instance recursively. + * + * @param key JSON name + * @param value JSON node + * @param listener JSON listener + * @throws SvcLogicException when processing a single instance fails + */ + private void processMultiNodes(String key, JsonNode value, + JsonListener listener) + throws SvcLogicException { + NodeType nodeType; + Iterator<JsonNode> multiNodes = value.elements(); + while (multiNodes.hasNext()) { + if (isLeafListNode((ArrayNode) value)) { + nodeType = MULTI_INSTANCE_LEAF_NODE; + } else { + nodeType = MULTI_INSTANCE_NODE; + } + JsonNode multiNode = multiNodes.next(); + processNode(key, multiNode, nodeType, listener); + } + } + + /** + * Processes each node by first entering the JSON node through JSON + * listener, second a call back to walking the rest of the tree of the + * node and finally exiting the node. + * + * @param key JSON name + * @param node JSON node + * @param nodeType JSON node type + * @param listener JSON listener + * @throws SvcLogicException when entering a JSON node fails + */ + private void processNode(String key, JsonNode node, NodeType nodeType, + JsonListener listener) throws SvcLogicException { + listener.enterJsonNode(key, node, nodeType); + walk(listener, node); + listener.exitJsonNode(node); + } + + /** + * Returns true if the node corresponds to a leaf-list node; false + * otherwise. + * + * @param node JSON node + * @return true if node corresponds to leaf-list node; false otherwise + */ + private boolean isLeafListNode(ArrayNode node) { + Iterator<JsonNode> children = node.elements(); + while (children.hasNext()) { + JsonNodeType type = children.next().getNodeType(); + if (type != STRING && type != NUMBER) { + return false; + } + } + return true; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java new file mode 100644 index 000000000..03abf44fd --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlListener.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.dom4j.Namespace; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.List; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; + +/** + * Representation of default implementation of XML listener. + */ +public class DefaultXmlListener implements XmlListener { + + /** + * Serializer helper to convert to properties node. + */ + private SerializerHelper serializerHelper; + + /** + * Creates an instance of default XML listener with its serializer helper. + * + * @param serializerHelper serializer helper + */ + public DefaultXmlListener(SerializerHelper serializerHelper) { + this.serializerHelper = serializerHelper; + } + + @Override + public void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException { + switch (nodeType) { + case TEXT_NODE: + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + element.getText(), null, null); + break; + + case OBJECT_NODE: + List cont = element.content(); + if (cont != null && cont.size() == 2 && + isValueNsForLeaf(cont, element)) { + return; + } + serializerHelper.addNode(element.getName(), + element.getNamespace().getURI(), + null, null, null); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + nodeType.toString())); + } + } + + /** + * Returns true if element has value namespace and adds the node to + * property tree; false otherwise. + * + * @param cont content of the element + * @param element element + * @return true if element has value namespace; false otherwise + * @throws SvcLogicException + */ + private boolean isValueNsForLeaf(List cont, Element element) + throws SvcLogicException { + for (Object c : cont) { + if (c instanceof Namespace) { + String value = element.getText(); + if (value != null) { + String[] val = value.split(":"); + String valPrefix = val[0]; + String actVal = val[1]; + if (valPrefix != null && actVal != null && + valPrefix.equals(((Namespace) c).getPrefix())) { + serializerHelper.addNode( + element.getName(), + element.getNamespace().getURI(), + actVal, + ((Namespace) c).getURI(), null); + return true; + } + } + } + } + return false; + } + + @Override + public void exitXmlElement(Element element) throws SvcLogicException { + serializerHelper.exitNode(); + } + + @Override + public SerializerHelper serializerHelper() { + return serializerHelper; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java new file mode 100644 index 000000000..cdc713f31 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DefaultXmlWalker.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.Iterator; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlNodeType; + +/** + * Implementation of XML walker to walk through the nodes and process it. + */ +public class DefaultXmlWalker implements XmlWalker { + + @Override + public void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException { + listener.enterXmlElement(xmlElement, getXmlNodeType(xmlElement)); + if (xmlElement.hasContent() && !xmlElement.isTextOnly()) { + Iterator i = xmlElement.elementIterator(); + while (i.hasNext()) { + Element childElement = (Element) i.next(); + walk(listener, childElement); + } + } + listener.exitXmlElement(xmlElement); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java new file mode 100644 index 000000000..06a811e15 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfListenerFactory.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + +/** + * Represents the data format listener factory which will return JSON or XML + * listener according to the serializer helper. + */ +public final class DfListenerFactory { + + /** + * Creates a new DfListenerFactory. + */ + private DfListenerFactory() { + } + + /** + * Returns the instance of the data format listener factory. + * + * @return instance of the data format listener factory + */ + public static DfListenerFactory instance() { + return DfListenerFactory.LazyHolder.INSTANCE; + } + + /** + * Bill pugh singleton pattern. Instance will not be instantiated until + * the lazy holder class is loaded via a call to the instance of method + * below. + */ + private static class LazyHolder { + private static final DfListenerFactory INSTANCE = + new DfListenerFactory(); + } + + /** + * Returns the data format listener by deciding it based on the format of + * the parameter. + * + * @param serHelper serializer helper + * @param params parameters + * @return data format listener + * @throws SvcLogicException when the data format type is wrong + */ + public Listener getListener(SerializerHelper serHelper, + YangParameters params) + throws SvcLogicException { + Listener listener; + switch (params.format) { + case JSON: + listener = new DefaultJsonListener(serHelper); + break; + + case XML: + listener = new DefaultXmlListener(serHelper); + break; + + default: + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); + } + return listener; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java new file mode 100644 index 000000000..4d95235e5 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerFactory.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.FORMAT_ERR; + +/** + * Represents the data format serializer factory which will return JSON or XML + * serializer according to the serializer context. + */ +public final class DfSerializerFactory { + + /** + * Creates a new DfSerializerFactory. + */ + private DfSerializerFactory() { + } + + /** + * Returns the instance of the data format serializer factory. + * + * @return instance of the data format serializer factory + */ + public static DfSerializerFactory instance() { + return DfSerializerFactory.LazyHolder.INSTANCE; + } + + /** + * Bill pugh singleton pattern. Instance will not be instantiated until + * the lazy holder class is loaded via a call to the instance of method + * below. + */ + private static class LazyHolder { + private static final DfSerializerFactory INSTANCE = + new DfSerializerFactory(); + } + + /** + * Returns the data format serializer by deciding it based on the format of + * the parameter. + * + * @param serCtx serializer context + * @param params parameters + * @return data format serializer + * @throws SvcLogicException when the data format type is wrong + */ + public DataFormatSerializer getSerializer(DataFormatSerializerContext serCtx, + YangParameters params) + throws SvcLogicException { + DataFormatSerializer serializer; + switch (params.format) { + case JSON: + serializer = new JsonSerializer(serCtx); + break; + + case XML: + serializer = new XmlSerializer(serCtx); + break; + + default: + throw new SvcLogicException(format(FORMAT_ERR, + params.format)); + } + return serializer; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java new file mode 100644 index 000000000..707c29444 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DfSerializerUtil.java @@ -0,0 +1,231 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +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.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Iterator; + +import static javax.xml.transform.OutputKeys.INDENT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.OBJECT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.XmlNodeType.TEXT_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; + +/** + * Utilities for data format serializer. + */ +public final class DfSerializerUtil { + + static final String JSON_WRITE_ERR = "Unable to write to JSON from " + + "properties."; + + static final String NODE_TYPE_ERR = "The node type %s is not supported."; + + static final String JSON_LIS_ERR = "The JSON serializer doesn't have " + + "JSON listener"; + + static final String XML_LIS_ERR = "The XML serializer doesn't have XML " + + "listener"; + + static final String PROP_NODE_ERR = "The property node doesn't have " + + "schema node bound to it."; + + static final String DF_ERR = "Type mismatch for the node %s. The schema " + + "node does not match with the data format node type %s."; + + static final String XML_PREFIX = "yangid"; + + private static final String YES = "yes"; + + private static final String INDENT_XMLNS = "{http://xml.apache" + + ".org/xslt}indent-amount"; + + private static final String XML_PARSE_ERR = "Unable to parse the xml to " + + "document : \n"; + + private static final String URI_ERR = "Unable to parse the URI"; + + /** + * Data format error message for unsupported types. + */ + public static final String FORMAT_ERR = "Only JSON and XML formats are " + + "supported. %s is not supported"; + + /** + * UTF header message for XML data format message. + */ + public static final String UTF_HEADER = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\"?>"; + + /** + * Error message when a JSON tree creation fails. + */ + public static final String JSON_TREE_ERR = "Unable to form JSON tree " + + "object from the JSON body provided."; + + /** + * Error message when a XML tree creation fails. + */ + public static final String XML_TREE_ERR = "Unable to form XML tree object" + + " from the XML body provided."; + + //No instantiation. + private DfSerializerUtil() { + } + + /** + * Returns the writer which contains the pretty formatted XML string. + * + * @param input input XML + * @param indent indentation level + * @return writer with XML + * @throws SvcLogicException when transformation of source fails + */ + public static Writer getXmlWriter(String input, String indent) + throws SvcLogicException { + try { + Transformer transformer = TransformerFactory.newInstance() + .newTransformer(); + transformer.setOutputProperty(INDENT, YES); + transformer.setOutputProperty(INDENT_XMLNS, indent); + StreamResult result = new StreamResult(new StringWriter()); + DOMSource source = new DOMSource(parseXml(input)); + transformer.transform(source, result); + return result.getWriter(); + } catch (TransformerException e) { + throw new SvcLogicException(XML_PARSE_ERR + input, e); + } + } + + /** + * Parses the XML and converts it into dom document which can be used for + * formatting the XML. + * + * @param in input XML + * @return dom document of XML + * @throws SvcLogicException when document building fails + */ + private static Document parseXml(String in) throws SvcLogicException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(new StringReader(in)); + return db.parse(is); + } catch (SAXException | IOException | ParserConfigurationException e) { + throw new SvcLogicException(XML_PARSE_ERR + in, e); + } + } + + /** + * Returns the resolved namespace object from the input received from the + * abstract data format. + * + * @param mName module name + * @param mUri module URI + * @param ctx schema context + * @param parent parent properties node + * @return namespace + * @throws SvcLogicException when resolving namespace fails + */ + static Namespace getResolvedNamespace(String mName, String mUri, + SchemaContext ctx, + PropertiesNode parent) + throws SvcLogicException { + if (mName == null && mUri == null) { + Namespace parentNs = parent.namespace(); + return new Namespace(parentNs.moduleName(), parentNs.moduleNs(), + parentNs.revision()); + } + + Iterator<Module> it; + Module mod; + if (mName != null) { + it = ctx.findModules(mName).iterator(); + } else { + URI modUri = null; + try { + modUri = new URI(mUri); + } catch (URISyntaxException e) { + throw new SvcLogicException(URI_ERR, e); + } + it = ctx.findModules(modUri).iterator(); + } + + if (!it.hasNext()) { + return null; + } + mod = it.next(); + + return new Namespace(mod.getName(), mod.getQNameModule().getNamespace(), + getRevision(mod.getRevision())); + } + + /** + * Returns the node type of a XML element. + * + * @param element XML element + * @return node type of the XML element + */ + static XmlNodeType getXmlNodeType(Element element) { + Element newElement = element.createCopy(); + newElement.remove(element.getNamespace()); + return newElement.hasContent() && newElement.isTextOnly() ? + TEXT_NODE : OBJECT_NODE; + } + + /** + * Resolves the super type to the base type from type definition. + * + * @param type super type + * @return base type definition + */ + static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) { + TypeDefinition superType = type; + while (superType.getBaseType() != null) { + superType = superType.getBaseType(); + } + return superType; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java new file mode 100644 index 000000000..89fd4c8c8 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonListener.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; + +/** + * Abstraction of an entity which provides call back methods, which in turn + * are called by JSON walker while walking the JSON tree. This interface + * needs to be implemented by protocol, implementing listener based call + * while doing JSON walk. + */ +public interface JsonListener extends Listener { + + /** + * Call back invoked during JSON node entry. All other related + * information can be obtained from the JSON node. + * + * @param nodeName JSON node name + * @param node JSON node + * @param nodeType JSON node type + * @throws SvcLogicException when node type is of wrong format + */ + void enterJsonNode(String nodeName, JsonNode node, NodeType nodeType) + throws SvcLogicException; + + /** + * Call back invoked during JSON node exit. All the related information + * can be obtained from the JSON node. + * + * @param node JSON node + * @throws SvcLogicException when JSON node exit doesn't happen + */ + void exitJsonNode(JsonNode node) throws SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java new file mode 100644 index 000000000..91adb8126 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonSerializer.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.JSON; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_LIS_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_TREE_ERR; + +/** + * Representation of JSON serializer which encodes properties to JSON and + * decodes properties from JSON with the data format serializer. + */ +public class JsonSerializer extends DataFormatSerializer { + + /** + * Creates an instance of data format serializer. + * + * @param serializerContext data format serializer context + */ + protected JsonSerializer(DataFormatSerializerContext serializerContext) { + super(JSON, serializerContext); + } + + @Override + public String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeJsonListener jsonLis = new PropertiesNodeJsonListener(); + nodeWalker.walk(jsonLis, propNode); + Writer writer = jsonLis.getWriter(); + return writer.toString(); + } + + @Override + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof JsonListener)) { + throw new SvcLogicException(JSON_LIS_ERR); + } + + JsonListener listener = (JsonListener) serializerContext().listener(); + JsonWalker walker = new DefaultJsonWalker(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode; + + try { + jsonNode = mapper.readTree(dataFormatBody); + } catch (IOException e) { + throw new SvcLogicException(JSON_TREE_ERR, e); + } + + walker.walk(listener, jsonNode); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java new file mode 100644 index 000000000..588070a12 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/JsonWalker.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides interface for JSON walk. This + * interface serves as a common tool for anyone who needs to parse the JSON + * node with depth-first algorithm. + */ +public interface JsonWalker { + + /** + * Walks the JSON data tree. Protocols implement JSON listener service + * and walks the JSON tree with input as implemented object. JSON walker + * provides call back to the implemented methods. + * + * @param listener JSON listener implemented by the protocol + * @param jsonNode root node of the JSON data tree + * @throws SvcLogicException when walking the JSON node fails + */ + void walk(JsonListener listener, JsonNode jsonNode) + throws SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java new file mode 100644 index 000000000..e5812dbb7 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/Listener.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Abstraction of listener. + */ +public interface Listener { + + /** + * Returns serializer helper for this listener. + * + * @return serializer helper + */ + SerializerHelper serializerHelper(); +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java new file mode 100644 index 000000000..1fd0d2dee --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/MdsalSerializerHelper.java @@ -0,0 +1,297 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; + +import java.util.Deque; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.DF_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.PROP_NODE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getResolvedNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.resolveBaseTypeFrom; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findDataChildSchemaByQName; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findSchemaForChild; +import static org.opendaylight.yangtools.yang.data.util.ParserStreamUtils.findSchemaNodeByNameAndNamespace; + +/** + * Representation of MDSAL based serializer helper, which adds properties + * node to the properties tree based on its types. + */ +public class MdsalSerializerHelper extends SerializerHelper<SchemaNode, SchemaContext> { + + /** + * Current properties node. + */ + private PropertiesNode propNode; + + /** + * Current schema node. + */ + private SchemaNode curSchemaNode; + + + /** + * Creates MDSAL serializer helper with root schema node, schema context + * and URI. + * + * @param n schema node of the URI's last node + * @param c schema context + * @param u URI of the request + */ + public MdsalSerializerHelper(SchemaNode n, SchemaContext c, + String u) { + super(n, c, u); + Namespace ns = new Namespace(n.getQName().getLocalName(), + n.getQName().getNamespace(), + getRevision(n.getQName().getRevision())); + propNode = new RootNode<>(n.getQName().getLocalName(), ns, + getSchemaNode(), u); + curSchemaNode = getSchemaNode(); + } + + @Override + protected SchemaNode getSchemaNode() { + return schemaNode; + } + + @Override + protected SchemaContext getSchemaCtx() { + return schemaCtx; + } + + @Override + protected SchemaNode getCurSchema() { + return curSchemaNode; + } + + @Override + protected void addNode(String name, String nameSpace, String value, + String valNameSpace, NodeType type) + throws SvcLogicException { + Namespace ns; + if (type == null) { + ns = getResolvedNamespace(null, nameSpace, + getSchemaCtx(), propNode); + } else { + ns = getResolvedNamespace(nameSpace, null, + getSchemaCtx(), propNode); + } + if (isChildPresent(name, ns)) { + addNodeToProperty(name, ns, value, valNameSpace, type); + } else { + throw new SvcLogicException(format( + "Unable to add the node %s", name)); + } + } + + @Override + protected void exitNode() throws SvcLogicException { + propNode = propNode.parent(); + if (propNode != null) { + NodeType type = propNode.nodeType(); + if (type == MULTI_INSTANCE_HOLDER_NODE || + type == MULTI_INSTANCE_LEAF_HOLDER_NODE) { + propNode = propNode.parent(); + } + } + if (propNode == null || propNode.appInfo() == null + || !(propNode.appInfo() instanceof SchemaNode)) { + throw new SvcLogicException(PROP_NODE_ERR); + } + curSchemaNode = (SchemaNode) propNode.appInfo(); + } + + @Override + protected PropertiesNode getPropertiesNode() { + return propNode; + } + + /** + * Adds the node to property node based on the type of the schema node, + * which is decided based on the name and namespace of the input + * information. + * + * @param name name of the node + * @param ns namespace of the node + * @param value value of the node if its a leaf/leaf-list + * @param valNamespace namespace of the value + * @param type type of the node + * @throws SvcLogicException when adding child fails + */ + private void addNodeToProperty(String name, Namespace ns, String value, + String valNamespace, NodeType type) + throws SvcLogicException { + Namespace valueNs; + if (type != null) { + validateNodeType(type); + } + if (curSchemaNode instanceof LeafSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(name, ns, + SINGLE_INSTANCE_LEAF_NODE, + value, valueNs, curSchemaNode); + } else if (curSchemaNode instanceof LeafListSchemaNode) { + valueNs = getValueNs(curSchemaNode, valNamespace, type); + propNode = propNode.addChild(null, name, ns, + MULTI_INSTANCE_LEAF_NODE, value, + valueNs, curSchemaNode); + } else if (curSchemaNode instanceof ListSchemaNode) { + propNode = propNode.addChild(null, name, ns, MULTI_INSTANCE_NODE, + curSchemaNode); + } else { + propNode = propNode.addChild(name, ns, SINGLE_INSTANCE_NODE, + curSchemaNode); + } + } + + /** + * Returns the namespace of the value namespace in case of identity ref. + * + * @param schemaNode schema node + * @param valNs value name space + * @param nodeType node type + * @return namespace of value namespace + * @throws SvcLogicException when namespace resolution fails for identityref + */ + private Namespace getValueNs(SchemaNode schemaNode, String valNs, + NodeType nodeType) throws SvcLogicException { + Namespace ns = null; + if (valNs != null) { + TypeDefinition type; + if (schemaNode instanceof LeafSchemaNode) { + type = ((LeafSchemaNode) schemaNode).getType(); + } else { + type = ((LeafListSchemaNode) schemaNode).getType(); + } + TypeDefinition<?> baseType = resolveBaseTypeFrom(type); + if (baseType instanceof IdentityrefTypeDefinition) { + if (nodeType == null) { + ns = getResolvedNamespace(null, valNs, getSchemaCtx(), + propNode); + } else { + ns = getResolvedNamespace(valNs, null, getSchemaCtx(), + propNode); + } + } + } + return ns; + } + + /** + * Validates that the node type from the data format matches with that of + * the corresponding schema node. + * + * @param type node type from the abstract data format + * @throws SvcLogicException when the node type is wrong + */ + private void validateNodeType(NodeType type) throws SvcLogicException { + boolean verify; + switch (type) { + case SINGLE_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafSchemaNode; + break; + + case MULTI_INSTANCE_LEAF_NODE: + verify = curSchemaNode instanceof LeafListSchemaNode; + break; + + case MULTI_INSTANCE_NODE: + verify = curSchemaNode instanceof ListSchemaNode; + break; + + case SINGLE_INSTANCE_NODE: + verify = (!(curSchemaNode instanceof LeafSchemaNode) && + !(curSchemaNode instanceof LeafListSchemaNode) && + !(curSchemaNode instanceof ListSchemaNode)); + break; + + default: + throw new SvcLogicException(format(NODE_TYPE_ERR, + type.toString())); + } + if (!verify) { + throw new SvcLogicException(format(DF_ERR, curSchemaNode + .getQName().getLocalName(), type.toString())); + } + } + + /** + * Returns true if the child schema is present with the name and + * namespace inside the current schema node, if present updates the + * current schema node; false otherwise. + * + * @param name name of the child schema node + * @param namespace namespace of the child schema node + * @return returns true if the child schema is available; false otherwise + */ + private boolean isChildPresent(String name, Namespace namespace) { + QName qname = QName.create(namespace.moduleNs(), + Revision.of(namespace.revision()), name); + SchemaNode childNode = null; + if (curSchemaNode instanceof DataSchemaNode) { + Deque<DataSchemaNode> dataSchema = findSchemaNodeByNameAndNamespace( + (DataSchemaNode) curSchemaNode, name, namespace.moduleNs()); + + if (dataSchema != null && !dataSchema.isEmpty()) { + childNode = dataSchema.pop(); + } + + if (dataSchema != null && !dataSchema.isEmpty()) { + childNode = findSchemaForChild(((ChoiceSchemaNode) childNode), + qname); + } + + } else { + childNode = findDataChildSchemaByQName(curSchemaNode, qname); + } + + if (childNode != null) { + curSchemaNode = childNode; + return true; + } + return false; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java new file mode 100644 index 000000000..0f03039e5 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeJsonListener.java @@ -0,0 +1,233 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; + +import static com.google.common.base.Strings.repeat; +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.JSON_WRITE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; + +/** + * Representation of JSON implementation of properties node listener. + */ +public class PropertiesNodeJsonListener implements PropertiesNodeListener{ + + /** + * JSON writer to write the JSON data format. + */ + private JsonWriter jsonWriter; + + /** + * Writer to write the JSON. + */ + private Writer writer; + + /** + * Creates the properties node JSON listener by instantiating and + * indenting the writer. + */ + public PropertiesNodeJsonListener() { + writer = new StringWriter(); + jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(repeat(" ", 4)); + } + + @Override + public void start(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.beginObject(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + try { + jsonWriter.endObject(); + jsonWriter.flush(); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + String val; + String nodeName = getNodeName(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginObject(); + break; + + case MULTI_INSTANCE_NODE: + jsonWriter.beginObject(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.name(nodeName).value(val); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.name(nodeName); + jsonWriter.beginArray(); + break; + + case MULTI_INSTANCE_LEAF_NODE: + val = getValueWithNs((LeafNode) node); + jsonWriter.value(val); + break; + + case ANY_XML_NODE: + jsonWriter.name(nodeName); + val = ((LeafNode) node).value(); + try { + jsonWriter.jsonValue(val); + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) throws SvcLogicException { + walkAugmentationNode(node); + try { + switch (node.nodeType()) { + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + jsonWriter.endObject(); + break; + + case MULTI_INSTANCE_HOLDER_NODE: + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + jsonWriter.endArray(); + break; + + case SINGLE_INSTANCE_LEAF_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case ANY_XML_NODE: + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } catch (IOException e) { + throw new SvcLogicException(JSON_WRITE_ERR, e); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Returns the abstract JSON node name to be used in JSON data format + * from the properties node. + * + * @param node properties node + * @return abstract JSON node + */ + private String getNodeName(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent instanceof RootNode || !parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + if (!parent.nonAppend()) { + return node.namespace().moduleName() + ":" + node.name(); + } + } + return node.name(); + } + + /** + * Returns the value of JSON leaf node with module name if required. + * + * @param node properties node + * @return value with namespace + */ + private String getValueWithNs(LeafNode node) { + Namespace valNs = node.valueNs(); + String modName = (valNs == null) ? null : valNs.moduleName(); + if (modName != null) { + return modName + ":" + node.value(); + } + return node.value(); + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java new file mode 100644 index 000000000..f098195e4 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/PropertiesNodeXmlListener.java @@ -0,0 +1,246 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.LeafNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.Namespace; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeListener; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.RootNode; + +import java.io.Writer; +import java.net.URI; +import java.util.Collection; +import java.util.Map; +import java.util.Stack; + +import static java.lang.String.format; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.NODE_TYPE_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.UTF_HEADER; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_PREFIX; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.getXmlWriter; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; + +/** + * Representation of XML implementation of properties node listener. + */ +public class PropertiesNodeXmlListener implements PropertiesNodeListener { + + /** + * XML data from the element. + */ + private String xmlData; + + /** + * Root element of the XML document. + */ + private Element rootElement; + + /** + * Writer to write the XML. + */ + private Writer writer; + + /** + * XML element stack to store the elements. + */ + private final Stack<Element> elementStack = new Stack<>(); + + /** + * Creates the properties node XML listener. + */ + public PropertiesNodeXmlListener() { + } + + @Override + public void start(PropertiesNode node) { + rootElement = addElement(null, node); + elementStack.push(rootElement); + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + xmlData = rootElement.asXML(); + xmlData = UTF_HEADER + xmlData; + writer = getXmlWriter(xmlData, "4"); + } + + @Override + public void enterPropertiesNode(PropertiesNode node) + throws SvcLogicException { + Element element = null; + String ns = getNodeNamespace(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + element = addElement(ns, node); + break; + + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + element = addElement(ns, node); + setValueWithNs(element, (LeafNode) node); + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + if (element != null) { + elementStack.push(element); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) + throws SvcLogicException { + walkAugmentationNode(node); + switch (node.nodeType()) { + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + case MULTI_INSTANCE_HOLDER_NODE: + break; + + case SINGLE_INSTANCE_NODE: + case MULTI_INSTANCE_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case SINGLE_INSTANCE_LEAF_NODE: + if (!elementStack.isEmpty()) { + elementStack.pop(); + } + break; + + default: + throw new SvcLogicException(format( + NODE_TYPE_ERR, node.nodeType().toString())); + } + } + + /** + * Returns the writer. + * + * @return writer + */ + public Writer getWriter() { + return writer; + } + + /** + * Adds an XML element to the stack with namespace if present. If the + * stack is empty it creates new document and adds element else adds to + * the parent element. + * + * @param ns namespace of the element + * @param node properties node + * @return new added element + */ + private Element addElement(String ns, PropertiesNode node) { + Element element; + if (elementStack.isEmpty()) { + Document doc = DocumentHelper.createDocument(); + if (ns != null) { + element = doc.addElement(node.name(), ns); + } else { + element = doc.addElement(node.name()); + } + } else { + element = elementStack.peek(); + if (ns != null) { + element = element.addElement(node.name(), ns); + } else { + element = element.addElement(node.name()); + } + } + + return element; + } + + /** + * Returns the abstract XML namespace to be used in XML data format from + * the properties node. + * + * @param node properties node + * @return abstract XML namespace + */ + private String getNodeNamespace(PropertiesNode node) { + PropertiesNode parent = node.parent(); + if (parent.nodeType() == MULTI_INSTANCE_HOLDER_NODE || + parent.nodeType() == MULTI_INSTANCE_LEAF_HOLDER_NODE) { + parent = parent.parent(); + } + if (parent instanceof RootNode || ! parent.namespace().moduleName() + .equals(node.namespace().moduleName())) { + return node.namespace().moduleNs().toString(); + } + return null; + } + + /** + * Sets the value to the element for a leaf node and adds the value + * namespace if required. + * + * @param element XML element + * @param node leaf properties node + */ + private void setValueWithNs(Element element, LeafNode node) { + Namespace valNs = node.valueNs(); + URI modNs = (valNs == null) ? null : valNs.moduleNs(); + String val = node.value(); + if (modNs != null) { + element.addNamespace(XML_PREFIX, modNs.toString()); + element.setText(XML_PREFIX + ":" + val); + } else { + element.setText(val); + } + } + + /** + * Gets all the augmentation of the given node and walks through it. + * + * @param node properties node + * @throws SvcLogicException when walking the properties node fails + */ + private void walkAugmentationNode(PropertiesNode node) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> augChild = augToChild.getValue(); + if (!augChild.isEmpty()) { + DefaultPropertiesNodeWalker walker = new + DefaultPropertiesNodeWalker(); + for (PropertiesNode p : augChild) { + enterPropertiesNode(p); + walker.walkChildNode(this, p); + exitPropertiesNode(p); + } + } + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java new file mode 100644 index 000000000..db9befb21 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/SerializerHelper.java @@ -0,0 +1,116 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; + +/** + * Abstraction of an entity which helps the data format serializers to obtain + * schema context details and to build properties from data. + * + * @param <T> type of schema node + * @param <P> type of schema context + */ +public abstract class SerializerHelper<T, P> { + + /** + * Schema node of the last element in the URI. + */ + protected T schemaNode; + + /** + * Root schema context. + */ + protected P schemaCtx; + + /** + * Root URI. + */ + protected String rootUri; + + /** + * Creates an instance of the serializer helper with the schema node, + * schema context and the URI. + * + * @param t schema node + * @param p schema context + * @param u root URI + */ + protected SerializerHelper(T t, P p, String u) { + schemaNode = t; + schemaCtx = p; + rootUri = u; + } + + /** + * Returns schema node of the last element in the URI. + * + * @return schema node + */ + protected abstract T getSchemaNode(); + + /** + * Returns the root schema context. + * + * @return schema context + */ + protected abstract P getSchemaCtx(); + + /** + * Returns the current schema context node. + * + * @return current schema context node + */ + protected abstract T getCurSchema(); + + /** + * Adds a node to the properties node tree. + * + * @param name name of the node + * @param nameSpace name space of the node, it can be either module + * name or namespace; null indicates parent namespace + * @param value value of the node; applicable for leaf/leaf-list node + * @param valNameSpace value namespace for identityref, could be module + * name or namespace + * @param type type of node if known like in case of JSON + * @throws SvcLogicException when adding node fails + */ + protected abstract void addNode(String name, String nameSpace, String value, + String valNameSpace, NodeType type) + throws SvcLogicException; + + /** + * Exits the node, in case if it's leaf node then it adds to the properties + * map. + * + * @throws SvcLogicException when properties node tree is improper + */ + protected abstract void exitNode() throws SvcLogicException; + + /** + * Returns the built properties corresponding to the data. + * + * @return properties node. + */ + protected abstract PropertiesNode getPropertiesNode(); +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java new file mode 100644 index 000000000..784e7af1f --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlListener.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides call back methods, which in turn + * are called by XML walker while walking the XML tree. This interface needs + * to be implemented by protocol implementing listener based call while doing + * XML walk. + */ +public interface XmlListener extends Listener { + + /** + * Callback invoked during a node entry. All the related information + * about the node can be obtained from the element. + * + * @param element current XML element + * @param nodeType node type of the element + * @throws SvcLogicException when node type is of wrong format + */ + void enterXmlElement(Element element, XmlNodeType nodeType) + throws SvcLogicException; + + /** + * Callback invoked during a node exit. All the related information about + * the node can be obtained from the element. + * + * @param element current xml element. + * @throws SvcLogicException when XML node exit doesn't happen + */ + void exitXmlElement(Element element) throws SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java new file mode 100644 index 000000000..7a6db3c86 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlNodeType.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Represents the XML node type. + */ +public enum XmlNodeType { + + /** + * Object XML node type. + */ + OBJECT_NODE, + + /** + * Text XML node type. + */ + TEXT_NODE +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java new file mode 100644 index 000000000..f3c6723e1 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlSerializer.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.DefaultPropertiesNodeWalker; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNode; +import org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.PropertiesNodeWalker; + +import java.io.Writer; +import java.util.List; +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormat.XML; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_LIS_ERR; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DfSerializerUtil.XML_TREE_ERR; + +/** + * Representation of XML serializer which encodes properties to XML and + * decodes properties from XML with the data format serializer. + */ +public class XmlSerializer extends DataFormatSerializer { + + /** + * Creates an instance of XML serializer. + * + * @param serializerContext data format serializer context + */ + protected XmlSerializer(DataFormatSerializerContext serializerContext) { + super(XML, serializerContext); + } + + @Override + public String encode(Map<String, String> param, + Map<String, List<Annotation>> annotations) + throws SvcLogicException { + PropertiesNode propNode = serializerContext().getPropNodeSerializer() + .encode(param); + PropertiesNodeWalker nodeWalker = new DefaultPropertiesNodeWalker<>(); + PropertiesNodeXmlListener xmlListener = new PropertiesNodeXmlListener(); + nodeWalker.walk(xmlListener, propNode); + Writer writer = xmlListener.getWriter(); + return removeRootNode(writer.toString(), propNode.name()); + } + + @Override + public Map<String, String> decode(String dataFormatBody) + throws SvcLogicException { + if (!(serializerContext().listener() instanceof XmlListener)) { + throw new SvcLogicException(XML_LIS_ERR); + } + + XmlListener listener = (XmlListener) serializerContext().listener(); + XmlWalker walker = new DefaultXmlWalker(); + Document document; + + try { + document = DocumentHelper.parseText(dataFormatBody); + } catch (DocumentException e) { + throw new SvcLogicException(XML_TREE_ERR, e); + } + walker.walk(listener, document.getRootElement()); + + return serializerContext().getPropNodeSerializer().decode( + listener.serializerHelper().getPropertiesNode()); + } + + /** + * Removes root node from the XML data format message and makes the + * string to be pretty print. + * + * @param xml XML data format message + * @param rootName root node name + * @return pretty print format XML message + */ + private static String removeRootNode(String xml, String rootName) { + xml = xml.replace("\n<" + rootName + ">", "\n"); + xml = xml.replace("</" + rootName + ">" + "\n", ""); + xml = xml.replaceAll("\n" + " ", "\n"); + xml = xml.replaceFirst("\n", ""); + return xml; + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java new file mode 100644 index 000000000..3835faa7e --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/XmlWalker.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.dom4j.Element; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of an entity which provides interface for XML walk. This + * interface serves as a common tool for anyone who needs to parse the XML + * node with depth-first algorithm. + */ +public interface XmlWalker { + + /** + * Walks the XML data tree. Protocols implement XML listener service and + * walks the XML tree with input as implemented object. XML walker + * provides call back to the implemented methods. + * + * @param listener XML listener implemented by the protocol + * @param xmlElement root element of the XML data tree + * @throws SvcLogicException when walking the XML node fails + */ + void walk(XmlListener listener, Element xmlElement) throws + SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java new file mode 100644 index 000000000..8eb3fb6e8 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/YangParameters.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import org.onap.ccsdk.sli.plugins.restapicall.Parameters; + +/** + * Representation of the YANG parameters for the restconf api call node. + */ +public class YangParameters extends Parameters { + /** + * Directory path of the YANG file. + */ + public String dirPath; + + /** + * Creates an instance of the YANG parameters. + */ + public YangParameters() { + super(); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java new file mode 100644 index 000000000..7be54690a --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DataNodeChild.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to data node. + */ +public interface DataNodeChild extends NodeChild { +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java new file mode 100644 index 000000000..2fa00bfb7 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeListener.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.COLON; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.UNDERSCORE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; + +/** + * Represents implementation of PropertiesNodeListener. + */ +public class DefaultPropertiesNodeListener implements PropertiesNodeListener { + + private Map<String, String> params = new HashMap<>(); + + @Override + public void start(PropertiesNode node) { + // do nothing + } + + @Override + public void end(PropertiesNode node) throws SvcLogicException { + exitPropertiesNode(node); + } + + @Override + public void enterPropertiesNode(PropertiesNode node) { + /* + * Only if it is leaf node or leaf-list node, + * then create a property entry and add to map + */ + if (node.nodeType() == SINGLE_INSTANCE_LEAF_NODE + || node.nodeType() == MULTI_INSTANCE_LEAF_NODE) { + String val = ((LeafNode) node).value(); + if (((LeafNode) node).valueNs() != null) { + val = ((LeafNode) node).valueNs().moduleName() + COLON + val; + } + String uri = node.uri().replaceAll(COLON, UNDERSCORE); + params.put(uri, val); + } + } + + @Override + public void exitPropertiesNode(PropertiesNode node) throws + SvcLogicException { + if (!node.augmentations().isEmpty()) { + for (Map.Entry<Object, Collection<PropertiesNode>> augmentationTochild + : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> childsFromAugmentations = augmentationTochild + .getValue(); + if (!childsFromAugmentations.isEmpty()) { + PropertiesNodeWalker walker = new DefaultPropertiesNodeWalker<>(); + for (PropertiesNode pNode : childsFromAugmentations) { + enterPropertiesNode(pNode); + walker.walk(this, pNode); + exitPropertiesNode(pNode); + } + } + } + } + } + + /** + * Returns properties. + * + * @return properties + */ + public Map<String, String> params() { + return params; + } + + /** + * Sets properties. + * + * @param params properties + */ + public void params(Map<String, String> params) { + this.params = params; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java new file mode 100644 index 000000000..5034530d5 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/DefaultPropertiesNodeWalker.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Implementation of properties node walker which helps in forming a new tree from properties node. + * + * @param <T> node child of properties node. + */ +public class DefaultPropertiesNodeWalker<T extends NodeChild> implements PropertiesNodeWalker { + + @Override + public void walk(PropertiesNodeListener listener, + PropertiesNode propertiesNode) throws SvcLogicException { + listener.start(propertiesNode); + walkChildNode(listener, propertiesNode); + listener.end(propertiesNode); + } + + /** + * Walks the children node from the parent node. + * + * @param listener properties node listener + * @param propertiesNode properties node + * @throws SvcLogicException when properties node walking fails + */ + public void walkChildNode(PropertiesNodeListener listener, + PropertiesNode propertiesNode) + throws SvcLogicException { + Map<String, T> children = getChildren(propertiesNode); + if (children != null) { + for (Map.Entry<String, T> entry : children.entrySet()) { + PropertiesNode node = ((PropertiesNode) entry.getValue()); + listener.enterPropertiesNode(node); + walkChildNode(listener, node); + listener.exitPropertiesNode(node); + } + } + if (propertiesNode instanceof RootNode) { + processAugments(propertiesNode, listener); + } + } + + /** + * Processes the augments present in the root node. + * + * @param node root node + * @param listener properties node listener + * @throws SvcLogicException when augment node walking fails + */ + private void processAugments(PropertiesNode node, + PropertiesNodeListener listener) + throws SvcLogicException { + for (Map.Entry<Object, Collection<PropertiesNode>> + augToChild : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + for (PropertiesNode p : child) { + listener.enterPropertiesNode(p); + walkChildNode(listener, p); + listener.exitPropertiesNode(p); + } + } + } + } + + /** + * Returns the children node according to the property node type. + * + * @param value property node + * @return property node children + */ + private Map<String,T> getChildren(PropertiesNode value) { + if (value instanceof RootNode) { + return ((RootNode) value).children(); + } + switch (value.nodeType()) { + case SINGLE_INSTANCE_NODE: + return ((InnerNode) value).children(); + case MULTI_INSTANCE_HOLDER_NODE: + return ((Map<String, T>) ((ListHolderNode) value).children()); + case MULTI_INSTANCE_NODE: + return ((Map<String, T>) ((MultiInstanceNode) value) + .children()); + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + return ((Map<String, T>) ((LeafListHolderNode) value) + .children()); + case SINGLE_INSTANCE_LEAF_NODE: + case MULTI_INSTANCE_LEAF_NODE: + case ANY_XML_NODE: + return null; + default: + throw new IllegalArgumentException("No more types allowed"); + } + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java new file mode 100644 index 000000000..52bec3412 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/HolderNode.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +/** + * Abstraction of an entity that represents holder node to multi instance node + * in properties data tree. + * + * @param <T> type of child + */ +public abstract class HolderNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<>(); + + protected HolderNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, + NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Returns child based on index. + * + * @return child based on index + */ + public T child(String index) { + return children.get(index); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java new file mode 100644 index 000000000..1cf99b2d4 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/InnerNode.java @@ -0,0 +1,215 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.addToAugmentations; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.createNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getAugmentationNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getUri; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.isNamespaceAsParent; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findCorrespondingAugment; + +/** + * Abstraction of an entity that represents an inner node to properties data + * tree. + * + * @param <T> type of child + */ +public abstract class InnerNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<String, T>(); + + protected InnerNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Sets children. + * + * @param children child nodes + */ + public void children(Map<String, T> children) { + this.children = children; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + PropertiesNode node = ((PropertiesNode) children.get(name)); + if (node != null) { + return node; + } + + // get augment schema, if it is augmented node + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, name); + } + + // create node based on type + if (node == null) { + String uri = getUri(this, name, namespace); + node = createNode(name, namespace, uri, this, appInfo, type); + } + + // If namespace is not same as parent then it is augmented node + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children.get(name)); + if (node != null) { + return node; + } + + AugmentationSchemaNode augSchema = null; + String uri = getUri(this, name, namespace); + node = new LeafNode(name, namespace, uri, this, + appInfo, type, value); + + if (type != NodeType.ANY_XML_NODE) { + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment( + ((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + } + node.valueNs(valueNs); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + String localname = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localname)); + + if (node == null) { + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localname); + } + + if (node == null) { + String uri = getUri(this, name, namespace); + node = new ListHolderNode(localname, namespace, uri, + this, appInfo, MULTI_INSTANCE_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localname, ((T) node)); + } + + node = node.addChild(index, localname, namespace, type, appInfo); + } else if (node instanceof ListHolderNode) { + ListHolderChild child = ((ListHolderNode) node).child(index); + node = (child != null ? ((MultiInstanceNode) child) : + node.addChild(index, localname, namespace, type, appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + String localName = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localName)); + + if (node == null) { + + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localName); + } + + if (node == null) { + String uri = getUri(this, name, namespace); + node = new LeafListHolderNode(localName, namespace, uri, this, + appInfo, MULTI_INSTANCE_LEAF_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localName, ((T) node)); + } + + node = node.addChild(index, localName, namespace, type, value, valueNs, appInfo); + } else if (node instanceof LeafListHolderNode) { + LeafNode child = ((LeafNode) ((HolderNode) node).child(index)); + node = (child != null ? child : node.addChild(index, localName, + namespace, type, + value, valueNs, + appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java new file mode 100644 index 000000000..e43249a3d --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to leaf list holder. + */ +public interface LeafListHolderChild extends NodeChild { + +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java new file mode 100644 index 000000000..46ab5bb63 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafListHolderNode.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of leaf list holder node which will hold multi instance leaf + * node in properties data tree. + */ +public class LeafListHolderNode extends HolderNode<LeafListHolderChild> implements DataNodeChild { + + private static final String node = " holder node"; + + /** + * Creates an instance of LeafListHolderNode. + * + * @param name name of the leaf-list node + * @param namespace namespace of the leaf-list node + * @param uri uri of the leaf-list node + * @param parent parent node of the leaf-list + * @param appInfo application info + * @param nodeType node type + */ + public LeafListHolderNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Container cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("List cannot be child of leaf-list" + + node); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children().get(index)); + if (index == null) { + index = String.valueOf(children().size()); + } + String uri = this.uri() + "[" + index + "]"; + node = (node != null) ? node : new LeafNode(name, namespace, uri, + this, appInfo, type, value); + node.valueNs(valueNs); + children().put(index, node); + return node; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java new file mode 100644 index 000000000..041175ca7 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/LeafNode.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of leaf node in properties data tree. + */ +public class LeafNode extends PropertiesNode implements LeafListHolderChild, DataNodeChild { + + private String value; + private Namespace valueNs; + private static final String svcLogicException = "Leaf cannot hold child nodes"; + + /** + * Creates an instance of leaf node. + * + * @param name name of the leaf node + * @param namespace namespace of the leaf node + * @param uri uri of the leaf node + * @param parent parent of the leaf node + * @param appInfo application info + * @param nodeType node type + * @param value value of the leaf + */ + public LeafNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType nodeType, + String value) { + super(name, namespace, uri, parent, appInfo, nodeType); + this.value = value; + } + + /** + * Returns value of the leaf. + * + * @return value of the leaf + */ + public String value() { + return value; + } + + /** + * Sets value of the leaf. + * + * @param value value of the leaf + */ + public void value(String value) { + this.value = value; + } + + /** + * Returns value namespace. + * + * @return value namespace + */ + public Namespace valueNs() { + return valueNs; + } + + /** + * Sets value namespace. + * + * @param valueNs value namespace + */ + public void valueNs(Namespace valueNs) { + this.valueNs = valueNs; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException(svcLogicException); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot hold child nodes"); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java new file mode 100644 index 000000000..ec9cc2a0f --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of entity representing child's to list holder. + */ +public interface ListHolderChild extends NodeChild { + +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java new file mode 100644 index 000000000..ba9da54cf --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/ListHolderNode.java @@ -0,0 +1,73 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Representation of list holder node which will hold multi instance node in + * properties data tree. + */ +public class ListHolderNode extends HolderNode<ListHolderChild> implements DataNodeChild { + + protected ListHolderNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf cannot be child of list holder node"); + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Container cannot be child of list holder node"); + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + MultiInstanceNode node = ((MultiInstanceNode) children().get(index)); + if (index == null) { + index = String.valueOf(children().size()); + } + String uri = this.uri() + "[" + index + "]"; + node = (node != null) ? node : new MultiInstanceNode(name, namespace, uri, + this, appInfo, type); + children().put(index, node); + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + throw new SvcLogicException("Leaf-list cannot be child of list holder node"); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java new file mode 100644 index 000000000..8a6e75668 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeSerializer.java @@ -0,0 +1,227 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.DOT_REGEX; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.SLASH; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getChildSchemaNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getIndex; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getListName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getNodeType; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getParsedValue; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getProcessedPath; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getRevision; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getValueNamespace; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.ANY_XML_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_LEAF_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.SINGLE_INSTANCE_NODE; + +/** + * Representation of mdsal based properties node serializer implementation. + */ +public class MdsalPropertiesNodeSerializer extends PropertiesNodeSerializer<SchemaNode, SchemaContext> { + + private static final Logger log = LoggerFactory.getLogger( + MdsalPropertiesNodeSerializer.class); + private SchemaNode curSchema; + private PropertiesNode node; + + /** + * Creates the properties node serializer. + * + * @param schemaNode schema node. + * @param schemaCtx schema context + * @param uri URL of the request + */ + public MdsalPropertiesNodeSerializer(SchemaNode schemaNode, + SchemaContext schemaCtx, String uri) { + super(schemaNode, schemaCtx, uri); + } + + @Override + public PropertiesNode encode(Map<String, String> paramMap) throws SvcLogicException { + curSchema = schemaNode(); + String nodeInUri[] = uri().split("\\/"); + String lastNodeName = nodeInUri[nodeInUri.length - 1]; + String rootUri = uri().replaceAll("\\/", "\\."); + node = createRootNode(lastNodeName, rootUri); + + paramMap = convertToValidParam(paramMap); + + updateModNameReq(paramMap, rootUri); + + for (Map.Entry<String, String> entry : paramMap.entrySet()) { + String[] names = entry.getKey().split("\\."); + for (int i = 0; i < names.length; i++) { + if (i < nodeInUri.length) { + if (!(nodeInUri[i].equals(names[i]))) { + break; + } + } else { + createPropertyNode(i, names.length, names[i], + entry.getValue()); + } + } + } + return node; + } + + private void updateModNameReq(Map<String, String> paramMap, + String rootUri) { + String isReqStr = rootUri + "." + "isNonAppend"; + String val = paramMap.get(isReqStr); + if (val != null && val.equals("true")) { + node.nonAppend(true); + } + } + + /** + * Converts all the params in the svc logic context into a valid param by + * replacing the underscore in module name to colon at necessary places. + * + * @param paramMap list of invalid parameters + * @return list of partially valid parameters + */ + private Map<String, String> convertToValidParam(Map<String, String> paramMap) { + Map<String, String> fixedParams = new HashMap<>(); + for(Map.Entry<String, String> entry : paramMap.entrySet()) { + String key = entry.getKey().replaceAll(DOT_REGEX, SLASH); + try { + SchemaPathHolder fixedUrl = getProcessedPath(key, schemaCtx()); + String fixedUri = fixedUrl.getUri().replaceAll( + SLASH, DOT_REGEX); + fixedParams.put(fixedUri, entry.getValue()); + } catch (IllegalArgumentException | RestconfDocumentedException + | NullPointerException e) { + log.info("Exception while processing properties by replacing " + + "underscore with colon. Process the properties as it is." + e); + fixedParams.put(entry.getKey(), entry.getValue()); + } + } + return fixedParams; + } + + @Override + public Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException { + PropertiesNodeWalker walker = new DefaultPropertiesNodeWalker<>(); + DefaultPropertiesNodeListener listener = new DefaultPropertiesNodeListener(); + walker.walk(listener, propertiesNode); + return listener.params(); + } + + private RootNode createRootNode(String lastNodeName, String rootUri) { + Module m = SchemaContextUtil.findParentModule(schemaCtx(), curSchema); + Namespace ns = new Namespace(m.getName(), m.getNamespace(), + getRevision(m.getRevision())); + return new RootNode(lastNodeName, ns, schemaNode(), rootUri); + } + + private void createPropertyNode(int index, int length, String name, + String value) throws SvcLogicException { + + Namespace ns = getNamespace(getListName(name), schemaCtx(), + node, curSchema); + String localName = resolveName(ns, name); + SchemaNode schema = getChildSchemaNode(curSchema, localName, ns); + if (schema == null) { + return; + } + + switch (getNodeType(index, length, name, schema)) { + case SINGLE_INSTANCE_NODE: + node = node.addChild(localName, ns, + SINGLE_INSTANCE_NODE, schema); + curSchema = schema; + break; + + case MULTI_INSTANCE_NODE: + node = node.addChild(getIndex(name), localName, ns, + MULTI_INSTANCE_NODE, schema); + curSchema = schema; + break; + + case SINGLE_INSTANCE_LEAF_NODE: + addLeafNode(value, SINGLE_INSTANCE_LEAF_NODE, localName, + ns, schema, name); + break; + + case MULTI_INSTANCE_LEAF_NODE: + addLeafNode(value, MULTI_INSTANCE_LEAF_NODE, localName, + ns, schema, name); + break; + + case ANY_XML_NODE: + node = node.addChild(localName, ns, ANY_XML_NODE, + value, null, schema); + node = node.endNode(); + curSchema = ((SchemaNode) node.appInfo()); + break; + + default: + throw new SvcLogicException("Invalid node type"); + } + } + + /** + * Adds leaf property node to the current node. + * + * @param value value of the leaf node + * @param type single instance or multi instance leaf node + * @param localName name of the leaf node + * @param ns namespace of the leaf node + * @param schema schema of the leaf node + * @param name name of the leaf in properties + * @throws SvcLogicException exception while adding leaf node + */ + private void addLeafNode(String value, NodeType type, + String localName, Namespace ns, + SchemaNode schema, String name) throws SvcLogicException { + Namespace valNs = getValueNamespace(value, schemaCtx()); + value = getParsedValue(valNs, value); + if (SINGLE_INSTANCE_LEAF_NODE == type) { + node = node.addChild(localName, ns, SINGLE_INSTANCE_LEAF_NODE, + value, valNs, schema); + } else { + node = node.addChild(getIndex(name), localName, ns, + MULTI_INSTANCE_LEAF_NODE, value, + valNs, schema); + } + node = node.endNode(); + curSchema = ((SchemaNode) node.appInfo()); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java new file mode 100644 index 000000000..e6fa064f5 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MdsalPropertiesNodeUtils.java @@ -0,0 +1,578 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.Optional; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils; +import org.opendaylight.yangtools.yang.data.util.ParserStreamUtils; +import org.opendaylight.yangtools.yang.data.util.codec.IdentityCodecUtil; +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static java.util.regex.Pattern.quote; +import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier.toInstanceIdentifier; + +/** + * Represents utilities for properties node tree. + */ +public final class MdsalPropertiesNodeUtils { + + static final String COLON = ":"; + + static final String UNDERSCORE = "_"; + + static final String SLASH = "/"; + + static final String DOT_REGEX = "\\."; + + private static final String INFO_MSG = "The %s formed is currently not" + + " valid"; + + private static final String EXC_MSG = "Unable to form a formatted path"; + + /** + * Logger for the Mdsal properties util class. + */ + private static final Logger log = LoggerFactory.getLogger( + MdsalPropertiesNodeUtils.class); + + private MdsalPropertiesNodeUtils() { + } + + /** + * Returns the index from multi instance property name. + * + * @param name name of the property + * @return index from multi instance property name + */ + public static String getIndex(String name) { + return name.substring(name.indexOf("[") + 1, + name.indexOf("]")); + } + + /** + * Returns the multi instance property name. + * + * @param name name of the property + * @return the multi instance property name + */ + public static String getListName(String name) { + String[] s = name.split("\\["); + return s[0]; + } + + /** + * Returns true if property is multi instance. + * + * @param name name of the property + * @return true if property is multi instance + */ + public static boolean isListEntry(String name) { + String s[] = name.split("\\["); + return s.length > 1; + } + + /** + * Returns name of the property after pruning namespace and + * index if the property is multi instance. + * + * @param name name of the property + * @return name of the property + */ + static String resolveName(String name) { + String localName = getListName(name); + final int lastIndexOfColon = localName.lastIndexOf(":"); + if (lastIndexOfColon != -1) { + localName = localName.substring(lastIndexOfColon + 1); + } + return localName; + } + + /** + * Returns name of the property after pruning namespace and index if the + * property is multi instance by knowing the module name from namespace. + * + * @param ns namespace + * @param name name of the node + * @return resolved name + */ + static String resolveName(Namespace ns, String name) { + String localName = getListName(name); + String modName = ns.moduleName(); + if ((localName.contains(COLON) || localName.contains(UNDERSCORE)) + && localName.startsWith(modName)) { + localName = localName.substring(modName.length()+1); + } + return localName; + } + + /** + * Adds current node to parent's augmentation map. + * + * @param augSchema augment schema + * @param parent parent property node + * @param curNode current property node + */ + public static void addToAugmentations(AugmentationSchemaNode augSchema, + PropertiesNode parent, + PropertiesNode curNode) { + Collection<PropertiesNode> childsFromAugmentation = parent + .augmentations().get(augSchema); + if (!childsFromAugmentation.isEmpty()) { + for (PropertiesNode pNode : childsFromAugmentation) { + if (pNode.name().equals(curNode.name())) { + return; + } + } + } + parent.augmentations().put(augSchema, curNode); + } + + + /** + * Returns augmented properties node if it is already + * added in properties tree. + * + * @param augSchema augmented schema node + * @param parent parent properties node + * @param name name of the properties + * @return augmented properties node if it is already added + */ + public static PropertiesNode getAugmentationNode( + AugmentationSchemaNode augSchema, + PropertiesNode parent, String name) { + if (augSchema == null) { + return null; + } + + Collection<PropertiesNode> childsFromAugmentation = parent + .augmentations().get(augSchema); + if (!childsFromAugmentation.isEmpty()) { + for (PropertiesNode pNode : childsFromAugmentation) { + if (pNode.name().equals(name)) { + return pNode; + } + } + } + + return null; + } + + /** + * Creates uri with specified name and namespace. + * + * @param parent parent properties node + * @param name name of the node + * @param ns namespace of the node + * @return uri with specified name and namespace + */ + public static String getUri(PropertiesNode parent, String name, + Namespace ns) { + String uri = name; + if (!(parent.namespace().moduleNs().equals(ns.moduleNs()))) { + uri = ns.moduleName() + ":" + name; + } + return parent.uri() + "." + uri; + } + + /** + * Creates new properties with specified parameters. + * + * @param name name of the properties node + * @param namespace namespace of the properties node + * @param uri uri of the properties node + * @param parent parent node + * @param appInfo application info + * @param type node type + * @return new properties node + * @throws SvcLogicException exception while creating properties node + */ + public static PropertiesNode createNode(String name, Namespace namespace, + String uri, PropertiesNode parent, + Object appInfo, NodeType type) + throws SvcLogicException { + switch (type) { + case SINGLE_INSTANCE_NODE: + return new SingleInstanceNode(name, namespace, uri, parent, appInfo, type); + case MULTI_INSTANCE_HOLDER_NODE: + return new ListHolderNode(name, namespace, uri, parent, appInfo, type); + case MULTI_INSTANCE_LEAF_HOLDER_NODE: + return new LeafListHolderNode(name, namespace, uri, parent, appInfo, type); + default: + throw new SvcLogicException("Invalid node type " + type); + } + } + + /** + * Returns true if namespace is same as parent's namespace. + * + * @param parent parent property node + * @param curNode current property node + * @return true if namespace is same as parent namespace + */ + public static boolean isNamespaceAsParent(PropertiesNode parent, + PropertiesNode curNode) { + return parent.namespace().moduleNs().equals(curNode.namespace().moduleNs()); + } + + /** + * Returns the schema path holder with a formatted url and the instance + * identifier context from a given uri or the parameters from svc logic + * context. + * + * @param uri unformatted uri or parameter + * @param context schema context + * @return schema path holder + */ + public static SchemaPathHolder getProcessedPath(String uri, + SchemaContext context) { + + String uri1 = uri.replaceAll(UNDERSCORE, COLON); + try { + InstanceIdentifierContext<?> id = toInstanceIdentifier( + uri1, context, null); + return new SchemaPathHolder(id, uri1); + } catch (IllegalArgumentException | RestconfDocumentedException + | NullPointerException e) { + log.info("Exception while converting uri to instance identifier" + + " context. Process each node in uri to get instance identifier" + + " context " + e); + return processNodesAndAppendPath(uri, context); + } + } + + /** + * Processes the nodes in the given uri and finds instance identifier + * context till it reaches the last node in uri. If its not able to find + * schema for the path, it appends the suffix part and puts it back in + * the param list. + * + * @param uri uri with underscore + * @param context schema context + * @return schema and path holder + */ + private static SchemaPathHolder processNodesAndAppendPath(String uri, + SchemaContext context) { + + String actPath = ""; + SchemaPathHolder id = new SchemaPathHolder(null, ""); + String[] uriParts = uri.split(SLASH); + String sec = ""; + if (uri.contains(UNDERSCORE)) { + sec = uri.substring(uriParts[0].length()+1); + } + for (int i = 0; i<uriParts.length; i++) { + + try { + id = processIdentifier(uriParts[i], context, actPath); + } catch (IllegalArgumentException e) { + log.info(format(EXC_MSG, e)); + id.setUri(actPath+ uriParts[i] + sec); + return id; + } + + actPath = actPath + id.getUri() + SLASH; + if (sec.startsWith(SLASH)) { + sec = sec.replaceFirst(SLASH, ""); + } + if (i+1 < uriParts.length) { + sec = sec.replaceFirst(quote(uriParts[i + 1]), ""); + } + } + id.setUri(actPath.substring(0,actPath.length() - 1)); + return id; + } + + /** + * Processes the schema and path holder for a given node in the path. It + * figures if the path is valid by replacing underscore in the node + * consecutively, till it finds the proper schema for the node. + * + * @param node node in the path + * @param context schema context + * @param prefix prefix for the node in the path + * @return schema and path holder + */ + private static SchemaPathHolder processIdentifier(String node, + SchemaContext context, + String prefix) { + + String[] values = node.split(UNDERSCORE); + String val = values[0]; + StringBuilder firstHalf = new StringBuilder(); + String secondHalf = ""; + if (node.contains(UNDERSCORE)) { + secondHalf = node.substring(values[0].length()+1); + } + InstanceIdentifierContext<?> id; + for (int i = 0; i< values.length-1; i++) { + val = values[i]; + val = firstHalf + val + COLON + secondHalf; + try { + id = toInstanceIdentifier(prefix + val, context, null); + return new SchemaPathHolder(id, val); + } catch (IllegalArgumentException | RestconfDocumentedException | + NullPointerException e) { + log.info(format(INFO_MSG, val, e)); + } + firstHalf.append(values[i]).append(UNDERSCORE); + secondHalf = secondHalf.replaceFirst( + values[i + 1] + UNDERSCORE,""); + } + val = val.replace(COLON,UNDERSCORE); + try { + id = toInstanceIdentifier(prefix + val, context, null); + return new SchemaPathHolder(id, val); + } catch (IllegalArgumentException | RestconfDocumentedException | + NullPointerException e1) { + throw new IllegalArgumentException(EXC_MSG, e1); + } + } + + /** + * Returns the namespace of the given node name. If the node name is + * separated by colon, the it splits with colon and forms the namespace. + * If the node name is formed with underscore, then it splits the node + * name consecutively to figure out the proper module name. + * + * @param childName node name + * @param ctx schema context + * @param parent parent properties node + * @param curSchema current schema + * @return namespace of the given node + */ + static Namespace getNamespace(String childName, SchemaContext ctx, + PropertiesNode parent, SchemaNode curSchema) { + + Namespace parentNs = parent.namespace(); + Namespace ns = new Namespace(parentNs.moduleName(), + parentNs.moduleNs(), parentNs.revision()); + int lastIndexOfColon = childName.lastIndexOf(COLON); + if (lastIndexOfColon != -1) { + String moduleName = childName.substring(0, lastIndexOfColon); + childName = childName.substring(lastIndexOfColon+1); + Namespace ns1 = getNs(moduleName, ctx); + if (ns1 != null) { + ns = ns1; + } + } + + SchemaNode child = getChildSchemaNode(curSchema, childName, ns); + + if (child == null && childName.contains(UNDERSCORE)) { + String[] children = childName.split(UNDERSCORE); + String second = childName.substring(children[0].length() + 1); + StringBuilder first = new StringBuilder(); + + for (int i =0; i< children.length; i++) { + String moduleName = first + children[i]; + Namespace newNs = getNs(moduleName, ctx); + if (newNs != null) { + return newNs; + } + first.append(children[i]).append(UNDERSCORE); + if (i + 1 < children.length) { + second = second.replaceFirst( + children[i + 1] + UNDERSCORE, ""); + } + } + return ns; + } + return ns; + } + + /** + * Returns the namespace by finding the given module in the schema context. + * + * @param modName module name + * @param ctx schema context + * @return namespace of the given node name + */ + private static Namespace getNs(String modName, SchemaContext ctx) { + Iterator<Module> it = ctx.findModules(modName).iterator(); + if (it.hasNext()) { + Module m = it.next(); + return new Namespace(modName, m.getQNameModule().getNamespace(), + getRevision(m.getRevision())); + } + return null; + } + + /** + * Returns child schema node. + * + * @param curSchema current schema node + * @param name name of the property + * @param namespace namespace of the property + * @return child schema node + */ + public static SchemaNode getChildSchemaNode(SchemaNode curSchema, + String name, + Namespace namespace) { + if (namespace == null) { + return null; + } + + QName qname = QName.create(namespace.moduleNs(), + Revision.of(namespace.revision()), name); + + // YANG RPC will not be instance of DataSchemaNode + if (curSchema instanceof DataSchemaNode) { + Deque<DataSchemaNode> schemaNodeDeque = ParserStreamUtils. + findSchemaNodeByNameAndNamespace(((DataSchemaNode) + curSchema), name, namespace.moduleNs()); + if (schemaNodeDeque.isEmpty()) { + // could not find schema node + return null; + } + + DataSchemaNode schemaNode = schemaNodeDeque.pop(); + if (schemaNodeDeque.isEmpty()){ + // Simple node + return schemaNode; + } + + // node is child of Choice/case + return SchemaUtils.findSchemaForChild(((ChoiceSchemaNode) schemaNode), + qname); + } else { + return SchemaUtils.findDataChildSchemaByQName(curSchema, qname); + } + } + + /** + * Returns the property node type. + * + * @param index current index + * @param length length of the properties + * @param name name of the property + * @return the property node type + */ + public static NodeType getNodeType(int index, int length, String name, + SchemaNode schema) { + if (index == length-1) { + if (schema instanceof AnyXmlSchemaNode){ + return NodeType.ANY_XML_NODE; + } + return (isListEntry(name) ? NodeType.MULTI_INSTANCE_LEAF_NODE : + NodeType.SINGLE_INSTANCE_LEAF_NODE); + } else { + return (isListEntry(name) ? NodeType.MULTI_INSTANCE_NODE : + NodeType.SINGLE_INSTANCE_NODE); + } + } + + /** + * Returns revision in string. + * + * @param r YANG revision + * @return revision in string + */ + public static String getRevision(Optional<Revision> r) { + return (r.isPresent()) ? r.get().toString() : null; + } + + /** + * Returns value namespace for leaf value. + * + * @param value value of the leaf + * @param ctx schema context + * @return value namespace + * @throws SvcLogicException if identity/module could not be found + */ + static Namespace getValueNamespace(String value, + SchemaContext ctx) + throws SvcLogicException { + String prefix = getPrefixFromValue(value); + if (prefix == null) { + return null; + } + + IdentitySchemaNode id = IdentityCodecUtil.parseIdentity(value, + ctx, + prefixToModule -> { + final Iterator<Module> modules = ctx.findModules(prefix).iterator(); + checkArgument(modules.hasNext(), "Could not find " + + "module %s", prefix); + return modules.next().getQNameModule(); + }); + + if (id == null) { + throw new SvcLogicException("Could not find identity"); + } + + return getModuleNamespace(id.getQName(), ctx); + } + + private static String getPrefixFromValue(String value) { + int lastIndexOfColon = value.lastIndexOf(":"); + if (lastIndexOfColon != -1) { + return value.substring(0, lastIndexOfColon); + } + return null; + } + + /** + * Returns module namespace from a given qName. + * + * @param qName qName of a node + * @param ctx schema context + * @return module namespace of the node + * @throws SvcLogicException when the module is not available + */ + public static Namespace getModuleNamespace(QName qName, SchemaContext ctx) + throws SvcLogicException { + Optional<Module> module = ctx.findModule(qName.getModule()); + if (!module.isPresent()) { + throw new SvcLogicException("Could not find module node"); + } + Module m = module.get(); + return new Namespace(m.getName(), m.getQNameModule().getNamespace(), + getRevision(m.getRevision())); + } + + static String getParsedValue(Namespace valNs, String value) { + if (valNs != null && value.contains(":")) { + String[] valArr = value.split(":"); + return valArr[1]; + } + return value; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java new file mode 100644 index 000000000..c251cdaea --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/MultiInstanceNode.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of multi instance node in properties data tree. + */ +public class MultiInstanceNode extends InnerNode<DataNodeChild> implements ListHolderChild { + + public MultiInstanceNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appinfo, NodeType nodeType) { + super(name, namespace, uri, parent, appinfo, nodeType); + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java new file mode 100644 index 000000000..4f27ee1e7 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/Namespace.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.net.URI; + +/** + * Representation of YANG namespace. + */ +public class Namespace { + private String moduleName; + private URI moduleNs; + private String revision; + + /** + * Creates an instance of namespace with specified module name, + * namespace and revision. + * + * @param modulename module name + * @param moduleNs module namespace + * @param revision revision + */ + public Namespace(String modulename, URI moduleNs, String revision) { + this.moduleName = modulename; + this.moduleNs = moduleNs; + this.revision = revision; + } + + /** + * Returns module name. + * + * @return module name + */ + public String moduleName() { + return moduleName; + } + + /** + * Sets module name. + * + * @param moduleName module name + */ + public void moduleName(String moduleName) { + this.moduleName = moduleName; + } + + /** + * Sets module namespace. + * + * @return module namespace + */ + public URI moduleNs() { + return moduleNs; + } + + /** + * Sets module namespace. + * + * @param moduleNs module namespace + */ + public void moduleNs(URI moduleNs) { + this.moduleNs = moduleNs; + } + + /** + * Returns revision. + * + * @return revision + */ + public String revision() { + return revision; + } + + /** + * Sets revision. + * + * @param revision revision + */ + public void revision(String revision) { + this.revision = revision; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java new file mode 100644 index 000000000..d482c6763 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeChild.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Abstraction of an entity that represents child's of a node. + */ +public interface NodeChild { + +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java new file mode 100644 index 000000000..0b6974e3e --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/NodeType.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of types of node in properties node tree. + */ +public enum NodeType { + SINGLE_INSTANCE_NODE, + MULTI_INSTANCE_NODE, + SINGLE_INSTANCE_LEAF_NODE, + MULTI_INSTANCE_LEAF_NODE, + MULTI_INSTANCE_HOLDER_NODE, + MULTI_INSTANCE_LEAF_HOLDER_NODE, + ANY_XML_NODE +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java new file mode 100644 index 000000000..7e0ad631e --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNode.java @@ -0,0 +1,280 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node data tree. This intermediate representation + * will enable data format serializers to be agnostic of DG context memory + * nuances and thereby will enable faster development of new data format + * serializers. + */ +public abstract class PropertiesNode { + + private String name; + private Namespace namespace; + private String uri; + private PropertiesNode parent; + private Object appInfo; + private NodeType nodeType; + private boolean nonAppend; + private Multimap<Object, PropertiesNode> augmentations = ArrayListMultimap.create(); + + /** + * Creates an instance of properties node. + * + * @param name name of node + * @param namespace namespace of node, null indicates parent namespace + * @param uri URI of this node, if null its calculated based on parent and + * current value of name and namespace + * @param parent parent's node + * @param appInfo application related information + * @param nodeType node type + */ + protected PropertiesNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, NodeType nodeType) { + this.name = name; + this.namespace = namespace; + this.uri = uri; + this.parent = parent; + this.appInfo = appInfo; + this.nodeType = nodeType; + } + + /** + * Sets name. + * + * @param name name of the node + */ + public void name(String name) { + this.name = name; + } + + /** + * Sets namespace. + * + * @param namespace namespace of the node + */ + public void namespace(Namespace namespace) { + this.namespace = namespace; + } + + /** + * Sets uri. + * + * @param uri uri of the node + */ + public void uri(String uri) { + this.uri = uri; + } + + /** + * Sets parent node. + * + * @param parent parent node + */ + public void parent(PropertiesNode parent) { + this.parent = parent; + } + + /** + * Sets application info. + * + * @param appInfo application info + */ + public void appInfo(Object appInfo) { + this.appInfo = appInfo; + } + + /** + * Sets to true if module name is required in forming a request; false + * otherwise. + * + * @param isNotReq true if required; false otherwise + */ + public void nonAppend(boolean isNotReq) { + this.nonAppend = isNotReq; + } + + /** + * Returns parent. + * + * @return parent node + */ + public PropertiesNode parent() { + return parent; + } + + /** + * Returns name. + * + * @return name of the node + */ + public String name() { + return name; + } + + /** + * Returns namespace. + * + * @return namespace of the node + */ + public Namespace namespace() { + return namespace; + } + + /** + * Returns uri. + * + * @return uri of the node + */ + public String uri() { + return uri; + } + + /** + * Returns application info. + * + * @return application info + */ + public Object appInfo() { + return appInfo; + } + + /** + * Returns node type. + * + * @return node type + */ + public NodeType nodeType() { + return nodeType; + } + + /** + * Returns if module name is required. + * + * @return status of module name if required + */ + public boolean nonAppend() { + return nonAppend; + } + + /** + * Returns augmentations. + * + * @return augmentations + */ + public Multimap<Object, PropertiesNode> augmentations() { + return augmentations; + } + + /** + * Sets augmentations. + * + * @param augmentations augmentations of the node + */ + public void augmentations(Multimap<Object, PropertiesNode> augmentations) { + this.augmentations = augmentations; + } + + /** + * Adds a child to a current node. + * + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param appInfo application info + * @return added properties node + */ + public abstract PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child with value to a current node. + * + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param value value of node + * @param valueNs value namespace + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valueNs, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child at a given index to a current node. To be used in case of + * leaf holder child's which is multi instance node. + * + * @param index index at which node is to be added + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String index, String name, + Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException; + + /** + * Adds a child at a given index to a current node. To be used in case of + * leaf holder child's which is multi instance node. + * + * @param index index at which node is to be added + * @param name name of child + * @param namespace namespace of child, null represents parent namespace + * @param type type of node + * @param value value of node + * @param valueNs value namespace + * @param appInfo application info + * @throws SvcLogicException if failed to add child + * @return added properties node + */ + public abstract PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException; + + /** + * Returns root node. + * + * @return root node + */ + public PropertiesNode endNode() { + PropertiesNode node = this; + while (node.parent() != null){ + node = node.parent(); + } + return node; + } +} + diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java new file mode 100644 index 000000000..7b97ffaf8 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeListener.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node listener. + */ +public interface PropertiesNodeListener { + + /** + * Pre-configurations required before starting the walking. + * + * @param node properties node + * @throws SvcLogicException when the pre-configuration fails + */ + void start(PropertiesNode node) throws SvcLogicException; + + /** + * Post-configurations required after starting the walking. + * + * @param node properties node + * @throws SvcLogicException when the post-configuration fails + */ + void end(PropertiesNode node) throws SvcLogicException; + + /** + * Enters the properties node. + * + * @param node properties node + * @throws SvcLogicException when entering the properties node fails + */ + void enterPropertiesNode(PropertiesNode node) throws SvcLogicException; + + /** + * Enters the properties node. + * + * @param node properties node + * @throws SvcLogicException when exiting the properties node fails + */ + void exitPropertiesNode(PropertiesNode node) throws SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java new file mode 100644 index 000000000..fe6fed484 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeSerializer.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +import java.util.Map; + +/** + * Abstraction of an entity to enable encoding and decoding of properties + * to an abstract properties node tree using YANG based schema. + * This serializer will be used by other data format serializers and will keep + * them abstract from properties nuances thereby enabling quick addition of any + * new data format serializer. + * + * @param <T> type of schema node + * @param <P> schema context of the model + */ +public abstract class PropertiesNodeSerializer<T, P> { + + /** + * Schema node from which the property is made. + */ + private T schemaNode; + + /** + * Schema context of the model. + */ + private P schemaCtx; + + /** + * URL pointing to the schema node. + */ + private String uri; + + /** + * Creates the properties node serializer. + * + * @param schemaNode schema node. + * @param schemaCtx schema context + * @param uri URL of the request + */ + public PropertiesNodeSerializer(T schemaNode, P schemaCtx, String uri) { + this.schemaNode = schemaNode; + this.schemaCtx = schemaCtx; + this.uri = uri; + } + + /** + * Encodes from properties to properties-node tree. + * + * @param paramMap parameter map + * @throws SvcLogicException fails to encode properties to properties node + * @return properties node + */ + public abstract PropertiesNode encode(Map<String, String> paramMap) throws SvcLogicException; + + /** + * Decodes from properties-node to properties map. + * + * @param propertiesNode properties-node + * @return parameter map + * @throws SvcLogicException fails to decode properties node to properties + */ + public abstract Map<String, String> decode(PropertiesNode propertiesNode) + throws SvcLogicException; + + /** + * Returns the schema node of the property + * + * @return schema node + */ + public T schemaNode(){ + return schemaNode; + } + + /** + * Returns the schema context + * + * @return schema node + */ + public P schemaCtx() { + return schemaCtx; + } + + /** + * Returns the URI. + * + * @return uri + */ + public String uri() { + return uri; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java new file mode 100644 index 000000000..36ee4dd9d --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesNodeWalker.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; + +/** + * Abstraction of properties node walker + */ +public interface PropertiesNodeWalker { + /** + * Walks the properties node with the listener. + * + * @param listener properties node listener. + * @param propertiesNode properties node + * @throws SvcLogicException when walking the properties node fails + */ + void walk(PropertiesNodeListener listener, PropertiesNode propertiesNode) + throws SvcLogicException; +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java new file mode 100644 index 000000000..c7f7340fd --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/RootNode.java @@ -0,0 +1,212 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; + +import java.util.HashMap; +import java.util.Map; + +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.addToAugmentations; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.createNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getAugmentationNode; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.getUri; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.isNamespaceAsParent; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.MdsalPropertiesNodeUtils.resolveName; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_HOLDER_NODE; +import static org.onap.ccsdk.sli.plugins.yangserializers.pnserializer.NodeType.MULTI_INSTANCE_LEAF_HOLDER_NODE; +import static org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils.findCorrespondingAugment; + +/** + * Abstraction of node representing properties data tree. + */ +public class RootNode<T extends NodeChild> extends PropertiesNode { + + private Map<String, T> children = new HashMap<String, T>(); + + /** + * Creates an instance of the root node to build the properties. + * + * @param name name of the node + * @param namespace namespace of the node + * @param appInfo application info + * @param uri URI of the node + */ + public RootNode(String name, Namespace namespace, + Object appInfo, String uri) { + super(name, namespace, uri, null, appInfo, null); + } + + /** + * Returns children. + * + * @return children + */ + public Map<String, T> children() { + return children; + } + + /** + * Sets children. + * + * @param children child nodes + */ + public void children(Map<String, T> children) { + this.children = children; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, + Object appInfo) throws SvcLogicException { + PropertiesNode node = ((PropertiesNode) children.get(name)); + if (node != null) { + return node; + } + + // get augment schema, if it is augmented node + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, name); + } + + // create node based on type, this api will be invoked only for these three types + if (node == null) { + String uri = getUri(this, name, namespace); + node = createNode(name, namespace, uri, this, appInfo, type); + } + + // If namespace is not same as parent then it is augmented node + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String name, Namespace namespace, + NodeType type, String value, + Namespace valuens, + Object appInfo) throws SvcLogicException { + LeafNode node = ((LeafNode) children.get(name)); + if (node != null) { + return node; + } + + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + } + + String uri = getUri(this, name, namespace); + node = new LeafNode(name, namespace, uri, this, + appInfo, type, value); + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(name, ((T) node)); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + Object appInfo) throws SvcLogicException { + String localname = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localname)); + if (node == null) { + String uri = getUri(this, name, namespace); + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localname); + } + + if (node == null) { + node = new ListHolderNode(localname, namespace, uri, + this, appInfo, MULTI_INSTANCE_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localname, ((T) node)); + } + node = node.addChild(index, localname, namespace, type, appInfo); + } else if (node instanceof ListHolderNode) { + ListHolderChild child = ((ListHolderNode) node).child(index); + node = (child != null ? ((MultiInstanceNode) child) : + node.addChild(index, localname, namespace, type, appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } + + @Override + public PropertiesNode addChild(String index, String name, + Namespace namespace, NodeType type, + String value, Namespace valueNs, + Object appInfo) throws SvcLogicException { + String localName = resolveName(name); + PropertiesNode node = ((PropertiesNode) children.get(localName)); + if (node == null) { + String uri = getUri(this, name, namespace); + AugmentationSchemaNode augSchema = null; + if (((DataSchemaNode) appInfo).isAugmenting()) { + augSchema = findCorrespondingAugment(((DataSchemaNode) this.appInfo()), + ((DataSchemaNode) appInfo)); + node = getAugmentationNode(augSchema, this, localName); + } + + if (node == null) { + node = new LeafListHolderNode(localName, namespace, uri, this, + appInfo, MULTI_INSTANCE_LEAF_HOLDER_NODE); + } + + if (augSchema != null && !isNamespaceAsParent(this, node)) { + addToAugmentations(augSchema, this, node); + } else { + children.put(localName, ((T) node)); + } + node = node.addChild(index, localName, namespace, type, value, valueNs, appInfo); + } else if (node instanceof LeafListHolderNode) { + LeafNode child = ((LeafNode) ((HolderNode) node).child(index)); + node = (child != null ? child : node.addChild(index, localName, + namespace, type, + value, valueNs, + appInfo)); + } else { + throw new SvcLogicException("Duplicate node exist with same node"); + } + return node; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java new file mode 100644 index 000000000..4ef1bc664 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SchemaPathHolder.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; + +/** + * Representation of a holder for a proper path and its corresponding schema. + */ +public class SchemaPathHolder { + + /** + * Schema context for the path. + */ + private InstanceIdentifierContext insId; + + /** + * Formatted path. + */ + private String uri; + + /** + * Constructs schema path holder with path and its schema. + * + * @param insId instance identifier context + * @param uri path + */ + public SchemaPathHolder(InstanceIdentifierContext insId, String uri) { + this.insId = insId; + this.uri = uri; + } + + /** + * Returns the instance identifier context of the path. + * + * @return schema of the path + */ + public InstanceIdentifierContext getInsId() { + return insId; + } + + /** + * Returns the formatted path. + * + * @return formatted path + */ + public String getUri() { + return uri; + } + + /** + * Sets the formatted path. + * + * @param uri formatted path + */ + public void setUri(String uri) { + this.uri = uri; + } +} diff --git a/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java new file mode 100644 index 000000000..6eb24c1a4 --- /dev/null +++ b/restconf-client/provider/src/main/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/SingleInstanceNode.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +/** + * Representation of single instance node in properties data tree. + */ +public class SingleInstanceNode extends InnerNode<DataNodeChild> implements DataNodeChild { + + public SingleInstanceNode(String name, Namespace namespace, String uri, + PropertiesNode parent, Object appInfo, + NodeType nodeType) { + super(name, namespace, uri, parent, appInfo, nodeType); + } +} diff --git a/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml b/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml new file mode 100755 index 000000000..45c335b13 --- /dev/null +++ b/restconf-client/provider/src/main/resources/OSGI-INF/blueprint/restconf-client-blueprint.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <reference xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0" + id="restapiCallNodeProvider" + interface="org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode" + ext:proxy-method="classes"/> + + <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" > + <argument ref="restapiCallNodeProvider"/> + </bean> + + <bean id="restconfDiscoveryNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" > + <argument ref="restconfapiCallNodeProvider"/> + </bean> + + <service ref="restconfapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode</value> + </interfaces> + </service> + + <service ref="restconfDiscoveryNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file diff --git a/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml b/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml new file mode 100755 index 000000000..45c335b13 --- /dev/null +++ b/restconf-client/provider/src/main/resources/org/opendaylight/blueprint/restconf-client-blueprint.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + --> + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <reference xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0" + id="restapiCallNodeProvider" + interface="org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode" + ext:proxy-method="classes"/> + + <bean id="restconfapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode" > + <argument ref="restapiCallNodeProvider"/> + </bean> + + <bean id="restconfDiscoveryNodeProvider" class="org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode" > + <argument ref="restconfapiCallNodeProvider"/> + </bean> + + <service ref="restconfapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode</value> + </interfaces> + </service> + + <service ref="restconfDiscoveryNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.restconfdiscovery.RestconfDiscoveryNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SseServerMock.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SseServerMock.java new file mode 100644 index 000000000..35ac221fb --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/SseServerMock.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.jersey.media.sse.EventOutput; +import org.glassfish.jersey.media.sse.OutboundEvent; +import org.glassfish.jersey.media.sse.SseFeature; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import java.io.IOException; + +@Path("events") +public class SseServerMock { + + @GET + @Produces(SseFeature.SERVER_SENT_EVENTS) + public EventOutput getServerSentEvents() throws IOException { + String data = "{" + + "\"ietf-restconf:notification\" : {" + + " \"eventTime\" : \"2017-10-25T08:22:33.44Z\"," + + " \"ietf-yang-push:push-change-update\": {" + + "\"subscription-id\":\"89\"," + + "\"datastore-changes\": {" + + "\"ietf-yang-patch:yang-patch\":{" + + "\"patch-id\":\"1\"," + + "\"edit\":[{" + + "\"edit-id\":\"edit1\"," + + "\"operation\":\"merge\"," + + "\"target\":\"/ietf-interfaces:interfaces-state\"," + + "\"value\": {" + + "\"ietf-interfaces:interfaces-state\":{"+ + "\"interface\": {" + + "\"name\":\"eth0\"," + + "\"oper-status\":\"down\"," + + "}" + + "}" + + "}" + + "}]"+ + "}" + + "}" + + "}" + + "}" + + "}"; + final EventOutput result = new EventOutput(); + result.write(new OutboundEvent.Builder().data(String.class, data).build()); + result.close(); + return result; + } +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/TestRestconfDiscoveryNode.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/TestRestconfDiscoveryNode.java new file mode 100644 index 000000000..aa89d67d7 --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/restconfdiscovery/TestRestconfDiscoveryNode.java @@ -0,0 +1,175 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.restconfdiscovery; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +import org.glassfish.jersey.media.sse.SseFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.Test; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode; + +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class TestRestconfDiscoveryNode { + + private static final URI CONTEXT = URI.create("http://localhost:8080/"); + + @Test + public void sendRequest() throws SvcLogicException, InterruptedException, IOException { + final ResourceConfig resourceConfig = new ResourceConfig( + SseServerMock.class, SseFeature.class); + HttpServer server = GrizzlyHttpServerFactory.createHttpServer(CONTEXT, + resourceConfig); + server.start(); + RestconfApiCallNode restconf = mock(RestconfApiCallNode.class); + doNothing().when(restconf) + .sendRequest(any(Map.class), any(SvcLogicContext.class)); + RestapiCallNode restApi = new RestapiCallNode(); + doReturn(restApi).when(restconf).getRestapiCallNode(); + + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute("prop.encoding-json", "encoding-json"); + ctx.setAttribute("restapi-result.response-code", "200"); + ctx.setAttribute("restapi-result.ietf-subscribed-notifications" + + ":establish-subscription.output.identifier", + "89"); + + Map<String, String> p = new HashMap<>(); + p.put("sseConnectURL", "http://localhost:8080/events"); + p.put("subscriberId", "networkId"); + p.put("responsePrefix", "restapi-result"); + p.put("restapiUser", "access"); + p.put("restapiPassword", "abc@123"); + p.put("customHttpHeaders", "X-ACCESS-TOKEN=x-ik2ps4ikvzupbx0486ft" + + "1ebzs7rt85futh9ho6eofy3wjsap7wqktemlqm4bbsmnar3vrtbyrzuk" + + "bv5itd6m1cftldpjarnyle3sdcqq9hftc4lebz464b5ffxmlbvg9"); + p.put("restapiUrl", "https://localhost:8080/restconf/operations/" + + "ietf-subscribed-notifications:establish-subscription"); + p.put("module", "testmodule"); + p.put("rpc", "testrpc"); + p.put("version", "1.0"); + p.put("mode", "sync"); + RestconfDiscoveryNode rdn = new RestconfDiscoveryNode(restconf); + rdn.establishSubscription(p, ctx); + Thread.sleep(1000); + rdn.deleteSubscription(p, ctx); + server.shutdown(); + } + + @Test(expected = SvcLogicException.class) + public void testSubGraphExecution() throws SvcLogicException{ + SvcLogicGraphInfo subDg = new SvcLogicGraphInfo(); + subDg.mode("sync"); + subDg.module("l3VpnService"); + subDg.rpc("createVpn"); + subDg.version("1.0"); + SvcLogicContext ctx = new SvcLogicContext(); + subDg.executeGraph(ctx); + } + + @Test(expected = SvcLogicException.class) + public void testEstablishSubscriptionWithoutSubscriberId() + throws SvcLogicException{ + SvcLogicContext ctx = new SvcLogicContext(); + Map<String, String> p = new HashMap<>(); + RestconfDiscoveryNode rdn = new RestconfDiscoveryNode( + new RestconfApiCallNode(new RestapiCallNode())); + rdn.establishSubscription(p, ctx); + } + + @Test + public void testResponseCode() { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute("restapi-result.response-code", "200"); + ctx.setAttribute("response-code", "404"); + RestconfDiscoveryNode rdn = new RestconfDiscoveryNode( + new RestconfApiCallNode(new RestapiCallNode())); + assertThat(rdn.getResponseCode("restapi-result", ctx), + is("200")); + assertThat(rdn.getResponseCode(null, ctx), + is("404")); + } + + @Test + public void testOutputIdentifier() { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute("restapi-result.ietf-subscribed-notifications:" + + "establish-subscription.output.identifier", + "89"); + ctx.setAttribute("ietf-subscribed-notifications:establish-subscripti" + + "on.output.identifier", "89"); + RestconfDiscoveryNode rdn = new RestconfDiscoveryNode( + new RestconfApiCallNode(new RestapiCallNode())); + assertThat(rdn.getOutputIdentifier("restapi-result", ctx), + is("89")); + } + + @Test + public void testGetTokenId() { + String customHttpHeaders = "X-ACCESS-TOKEN=x-ik2ps4ikvzupbx0486ft1ebzs7rt85" + + "futh9ho6eofy3wjsap7wqktemlqm4bbsmnar3vrtbyrzukbv5itd6m1cftldpjarny" + + "le3sdcqq9hftc4lebz464b5ffxmlbvg9"; + RestconfDiscoveryNode rdn = new RestconfDiscoveryNode( + new RestconfApiCallNode(new RestapiCallNode())); + + assertThat(rdn.getTokenId(customHttpHeaders), + is("x-ik2ps4ikvzupbx0486ft1ebzs7rt85futh9ho6eofy3wjsap7wqkt" + + "emlqm4bbsmnar3vrtbyrzukbv5itd6m1cftldpjarnyle3sdcqq9h" + + "ftc4lebz464b5ffxmlbvg9")); + } + + @Test + public void testSubscriptionInfo() throws SvcLogicException { + SubscriptionInfo info = new SubscriptionInfo(); + info.subscriberId("network-id"); + info.subscriptionId("8"); + info.filterUrl("/ietf-interfaces:interfaces"); + info.yangFilePath("/opt/yang"); + SvcLogicGraphInfo svcLogicGraphInfo = new SvcLogicGraphInfo(); + svcLogicGraphInfo.mode("sync"); + svcLogicGraphInfo.module("testModule"); + svcLogicGraphInfo.rpc("testRpc"); + svcLogicGraphInfo.version("1.0"); + info.callBackDG(svcLogicGraphInfo); + assertThat(info.subscriberId(), is("network-id")); + assertThat(info.subscriptionId(), is("8")); + assertThat(info.filterUrl(), is("/ietf-interfaces:interfaces")); + assertThat(info.yangFilePath(), is("/opt/yang")); + assertThat(info.callBackDG().module(), is("testModule")); + assertThat(info.callBackDG().mode(), is("sync")); + assertThat(info.callBackDG().rpc(), is("testRpc")); + assertThat(info.callBackDG().version(), is("1.0")); + } +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerTest.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerTest.java new file mode 100644 index 000000000..aa1e50d6a --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatSerializerTest.java @@ -0,0 +1,996 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.HttpResponse; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.GET; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PATCH; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.POST; +import static org.onap.ccsdk.sli.plugins.restapicall.HttpMethod.PUT; +import static org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiUtils.parseUrl; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.DECODE_ANYXML_RESPONSE; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.DECODE_FROM_JSON_RPC; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.DECODE_FROM_XML_RPC; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_ANYXML; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_ID_PUT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_RPC; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_YANG; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_YANG_AUG_POST; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_JSON_YANG_PUT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_ID_PUT; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_RPC; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_YANG; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_YANG_AUG_POST; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.ENCODE_TO_XML_YANG_PUT; + + +/** + * Unit test cases for data format serialization and restconf api call node. + */ +public class DataFormatSerializerTest { + + private Map<String, String> p; + + private RestconfApiCallNode restconf; + + private RestapiCallNode restApi; + + private DfCaptor dfCaptor; + + /** + * Sets up the pre-requisite for each test case. + * + * @throws SvcLogicException when test case fails + */ + @Before + public void setUp() throws SvcLogicException { + p = new HashMap<>(); + p.put("restapiUser", "user1"); + p.put("restapiPassword", "abc123"); + p.put("responsePrefix", "response"); + p.put("skipSending", "true"); + restApi = new RestapiCallNode(); + restconf = mock(RestconfApiCallNode.class); + dfCaptor = new DfCaptor(); + createMethodMocks(); + } + + /** + * Creates method mocks using mockito for RestconfApiCallNode class. + * + * @throws SvcLogicException when test case fails + */ + private void createMethodMocks() throws SvcLogicException { + doReturn(restApi).when(restconf).getRestapiCallNode(); + doCallRealMethod().when(restconf).sendRequest( + any(Map.class), any(SvcLogicContext.class)); + doCallRealMethod().when(restconf).sendRequest( + any(Map.class), any(SvcLogicContext.class), any(Integer.class)); + doAnswer(dfCaptor).when(restconf).serializeRequest( + any(Map.class), any(YangParameters.class), any(String.class), + any(InstanceIdentifierContext.class)); + doAnswer(dfCaptor).when(restconf).updateReq( + any(String.class), any(YangParameters.class), + any(InstanceIdentifierContext.class)); + } + + /** + * Creates mock using mockito with input data for decoding. + * + * @param decodeData input data + * @throws SvcLogicException when test case fails + */ + private void createMockForDecode(String decodeData) + throws SvcLogicException { + doReturn(decodeData).when(restconf).getResponse( + any(SvcLogicContext.class), any(YangParameters.class), + any(String.class), any(HttpResponse.class)); + doCallRealMethod().when(restconf).serializeResponse( + any(YangParameters.class), any(String.class), any(String.class), + any(InstanceIdentifierContext.class)); + } + + /** + * Verifies encoding of parameters to JSON data format with identity-ref + * and inter-file linking. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonId() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + ctx.setAttribute(pre + "l", "abc"); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_ID)); + } + + /** + * Verifies encoding of parameters to JSON data format any xml in it. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeForAnyXml() throws SvcLogicException { + String pre = "execution-service_process."; + SvcLogicContext ctx = createAnyXmlAttList(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/api/v1/execution-service/process"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_ANYXML)); + } + + /** + * Verifies encoding of parameters to JSON data format with identity-ref + * and inter-file linking for put operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonIdWithPut() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + ctx.setAttribute(pre + "l", "abc"); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_ID_PUT)); + } + + /** + * Verifies encoding of parameters to JSON data format with identity-ref + * and inter-file linking for patch operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonIdWithPatch() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + ctx.setAttribute(pre + "l", "abc"); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "patch"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_ID_PUT)); + } + + /** + * Verifies encoding of parameters to XML data format with identity-ref + * and inter-file linking. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlId() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_ID)); + } + + /** + * Verifies encoding of parameters to XML data format with identity-ref + * and inter-file linking for put operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlIdWithPut() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_ID_PUT)); + } + + /** + * Verifies encoding of parameters to XML data format with identity-ref + * and inter-file linking for patch operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlIdWithPatch() throws SvcLogicException { + String pre = "identity-test_test."; + SvcLogicContext ctx = createAttList(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "patch"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_ID_PUT)); + } + + /** + * Verifies decoding of parameters from JSON data format with identity-ref + * and inter-file linking. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToJsonId() throws SvcLogicException { + createMockForDecode(ENCODE_TO_JSON_ID); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "identity-test_test."; + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + assertThat(ctx.getAttribute(pre + "l"), is("abc")); + verifyAttList(ctx, pre); + } + + /** + * Verifies decoding of parameters from XML data format with identity-ref + * and inter-file linking. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToXmlId() throws SvcLogicException { + createMockForDecode(ENCODE_TO_XML_ID); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "identity-test_test."; + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/identity-test:test"); + restconf.sendRequest(p, ctx); + verifyAttList(ctx, pre); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYang() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG)); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment for put operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYangWithPut() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_PUT)); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment for patch operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYangWithPatch() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "patch"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_PUT)); + } + + /** + * Verifies encoding of parameters to JSON data format with augment as + * root child. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonWithAugAsRootChild() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_AUG_POST)); + } + + /** + * Verifies decoding of parameters from JSON data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToJsonYang() throws SvcLogicException { + createMockForDecode(ENCODE_TO_JSON_YANG); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "test-yang_cont1.cont2."; + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1"); + restconf.sendRequest(p, ctx); + verifyAttListYang(ctx, pre); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYang() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG)); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment for put operation-type + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYangWithPut() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_PUT)); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment for patch operation-type + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYangWithPatch() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_PUT)); + } + + /** + * Verifies encoding of parameters to XML data format with augment as + * root child. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlWithAugAsRootChild() throws SvcLogicException { + String pre = "test-yang_cont1.cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1/cont2/cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_AUG_POST)); + } + + /** + * Verifies decoding of parameters from XML data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToXmlYang() throws SvcLogicException { + createMockForDecode(ENCODE_TO_XML_YANG); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "test-yang_cont1.cont2."; + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:cont1"); + restconf.sendRequest(p, ctx); + verifyAttListYang(ctx, pre); + } + + /** + * Verifies encoding of and decoding from, JSON respectively for data + * format with containers, grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void codecToJsonRpc() throws SvcLogicException { + createMockForDecode(DECODE_FROM_JSON_RPC); + String inPre = "test-yang_create-sfc.input."; + String outPre = "test-yang_create-sfc.output."; + SvcLogicContext ctx = createAttListRpc(inPre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:create-sfc"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_RPC)); + verifyAttListRpc(ctx, outPre); + } + + /** + * Verifies encoding of and decoding from, JSON for ANYXML. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void codecForNormalAnyXml() throws SvcLogicException { + createMockForDecode(DECODE_ANYXML_RESPONSE); + String inPre = "execution-service_process."; + SvcLogicContext ctx = createAnyXmlAttList(inPre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("responsePrefix", "pp"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/api/v1/execution-service/process"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_ANYXML)); + verifyOutputOfAnyXml(ctx); + } + + /** + * Verifies encoding of and decoding from, XML respectively for data + * format with containers, grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void codecToXmlRpc() throws SvcLogicException { + createMockForDecode(DECODE_FROM_XML_RPC); + String inPre = "test-yang_create-sfc.input."; + String outPre = "test-yang_create-sfc.output."; + SvcLogicContext ctx = createAttListRpc(inPre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test-yang:create-sfc"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_RPC)); + verifyAttListRpc(ctx, outPre); + } + + /** + * Verifies URL parser returning path with only schema information for all + * kind of URL. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void validateUrlParser() throws SvcLogicException { + String actVal = "identity-test:test"; + String putId = "/for-put"; + String url1 = "http://echo.getpostman.com/restconf/operations/" + + actVal; + String url2 = "http://echo.getpostman.com/restconf/data/" + actVal; + String url3 = "https://echo.getpostman.com/restconf/operations/" + + actVal; + String url4 = "https://echo.getpostman.com/restconf/data/" + actVal + + putId; + String url5 = "http://localhost:8282/restconf/operations/" + actVal; + String url6 = "https://localhost:8282/restconf/operations/" + actVal; + String url7 = "http://localhost:8282/restconf/data/" + actVal + + putId; + String url8 = "https://localhost:8282/restconf/data/" + actVal; + String url9 = "http://182.2.61.24:2250/restconf/data/" + actVal; + String url10 = "https://182.2.61.24:2250/restconf/operations/" + actVal; + String url11 = "https://182.2.61.24:2250/api/v1/execution-service" + + "/process"; + String url12 = "https://182.2.61.24:2250/api/v1/execution-service" + + "/process/payload"; + String url13 = "https://182.2.61.24:2250/api/v1/execution-service" + + "/process/payload/"; + String val1 = parseUrl(url1, POST); + String val2 = parseUrl(url2, GET); + String val3 = parseUrl(url3, PATCH); + String val4 = parseUrl(url4, PUT); + String val5 = parseUrl(url5, GET); + String val6 = parseUrl(url6, POST); + String val7 = parseUrl(url7, PUT); + String val8 = parseUrl(url8, POST); + String val9 = parseUrl(url9, GET); + String val10 = parseUrl(url10, POST); + String val11 = parseUrl(url11, POST); + String val12 = parseUrl(url12, POST); + String val13 = parseUrl(url13, POST); + assertThat(val1, is(actVal)); + assertThat(val2, is(actVal)); + assertThat(val3, is(actVal)); + assertThat(val4, is(actVal + putId)); + assertThat(val5, is(actVal)); + assertThat(val6, is(actVal)); + assertThat(val7, is(actVal + putId)); + assertThat(val8, is(actVal)); + assertThat(val9, is(actVal)); + assertThat(val10, is(actVal)); + assertThat(val11, is("execution-service:process")); + assertThat(val12, is("execution-service:process/payload")); + assertThat(val13, is("execution-service:process/payload/")); + } + + /** + * Creates attribute list for encoding JSON or XML with ANYXML YANG + * file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAnyXmlAttList(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + String pre1 = pre + "commonHeader."; + String pre2 = pre + "actionIdentifiers."; + ctx.setAttribute(pre + "isNonAppend", "true"); + ctx.setAttribute(pre1 + "originatorId", "SDNC_DG"); + ctx.setAttribute(pre1 + "requestId", "123456-1000"); + ctx.setAttribute(pre1 + "subRequestId", "sub-123456-1000"); + ctx.setAttribute(pre2 + "blueprintName", + "baseconfiguration"); + ctx.setAttribute(pre2 + "blueprintVersion", "1.0.0"); + ctx.setAttribute(pre2 + "actionName", "assign-activate"); + ctx.setAttribute(pre2 + "mode", "sync"); + ctx.setAttribute(pre + "payload." + + "template-prefix", "vDNS-test"); + ctx.setAttribute(pre + "payload.resource-assignment-request" + + ".resource-assignment-properties", + "{\n" + + " \"service-instance-id\": " + + "\"1234\",\n" + + " \"vnf-id\": \"3526\",\n" + + " \"customer-name\": \"htipl\",\n" + + " \"subscriber-name\": \"huawei\"\n" + + " }"); + return ctx; + } + + /** + * Creates attribute list for encoding JSON or XML with identity-ref YANG + * file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAttList(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + String pre1 = pre + "con1.interfaces."; + ctx.setAttribute(pre + "con1.interface", "identity-types:physical"); + ctx.setAttribute(pre1 + "int-list[0].iden", "optical"); + ctx.setAttribute(pre1 + "int-list[0].available.ll[0]", "Giga"); + ctx.setAttribute(pre1 + "int-list[0].available.ll[1]", + "identity-types:Loopback"); + ctx.setAttribute(pre1 + "int-list[0].available.ll[2]", + "identity-types-second:Ethernet"); + ctx.setAttribute(pre1 + "int-list[0].available.leaf1", "58"); + ctx.setAttribute(pre1 + "int-list[0].available.leaf2", + "identity-types-second:iden2"); + + ctx.setAttribute(pre1 + "int-list[1].iden", "214748364"); + ctx.setAttribute(pre1 + "int-list[1].available.ll[0]", "Giga"); + ctx.setAttribute(pre1 + "int-list[1].available.ll[1]", + "identity-types:Loopback"); + ctx.setAttribute(pre1 + "int-list[1].available.ll[2]", + "identity-types-second:Ethernet"); + ctx.setAttribute(pre1 + "int-list[1].available.leaf1", + "8888"); + ctx.setAttribute(pre1 + "int-list[1].available.leaf2", + "identity-types-second:iden2"); + return ctx; + } + + /** + * Creates attribute list for encoding JSON or XML with container, + * grouping and augmented YANG file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAttListYang(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute(pre + "cont3.leaf10", "abc"); + ctx.setAttribute(pre + "list1[0].leaf1", "true"); + ctx.setAttribute(pre + "list1[0].leaf2", "abc"); + ctx.setAttribute(pre + "list1[0].leaf3", "abc"); + ctx.setAttribute(pre + "list1[0].ll1[0]", "abc"); + ctx.setAttribute(pre + "list1[0].ll1[1]", "abc"); + ctx.setAttribute(pre + "list1[0].ll2[0]", "abc"); + ctx.setAttribute(pre + "list1[0].ll2[1]", "abc"); + ctx.setAttribute(pre + "list1[0].cont4.leaf11", "abc"); + ctx.setAttribute(pre + "list1[0].list4[0].leaf8", "abc"); + ctx.setAttribute(pre + "list1[0].list4[1].leaf8", "abc"); + ctx.setAttribute(pre + "list1[0].list5[0].leaf9", "abc"); + ctx.setAttribute(pre + "list1[0].list5[1].leaf9", "abc"); + ctx.setAttribute(pre + "list1[1].leaf1", "true"); + ctx.setAttribute(pre + "list1[1].leaf2", "abc"); + ctx.setAttribute(pre + "list1[1].leaf3", "abc"); + ctx.setAttribute(pre + "list1[1].ll1[0]", "abc"); + ctx.setAttribute(pre + "list1[1].ll1[1]", "abc"); + ctx.setAttribute(pre + "list1[1].ll2[0]", "abc"); + ctx.setAttribute(pre + "list1[1].ll2[1]", "abc"); + ctx.setAttribute(pre + "list1[1].cont4.leaf11", "abc"); + ctx.setAttribute(pre + "list1[1].list4[0].leaf8", "abc"); + ctx.setAttribute(pre + "list1[1].list4[1].leaf8", "abc"); + ctx.setAttribute(pre + "list1[1].list5[0].leaf9", "abc"); + ctx.setAttribute(pre + "list1[1].list5[1].leaf9", "abc"); + ctx.setAttribute(pre + "list2[0].leaf4", "abc"); + ctx.setAttribute(pre + "list2[1].leaf4", "abc"); + ctx.setAttribute(pre + "leaf5", "abc"); + ctx.setAttribute(pre + "leaf6", "abc"); + ctx.setAttribute(pre + "ll3[0]", "abc"); + ctx.setAttribute(pre + "ll3[1]", "abc"); + ctx.setAttribute(pre + "ll4[0]", "abc"); + ctx.setAttribute(pre + "ll4[1]", "abc"); + ctx.setAttribute(pre + "cont4.leaf10", "abc"); + ctx.setAttribute(pre + "list6[0].leaf11", "abc"); + ctx.setAttribute(pre + "list6[1].leaf11", "abc"); + ctx.setAttribute(pre + "leaf12", "abc"); + ctx.setAttribute(pre + "ll5[0]", "abc"); + ctx.setAttribute(pre + "ll5[1]", "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont5.leaf13", "true"); + ctx.setAttribute(pre + "cont4.test-augment_list7[0].leaf14", "test"); + ctx.setAttribute(pre + "cont4.test-augment_list7[1].leaf14", "create"); + ctx.setAttribute(pre + "cont4.test-augment_leaf15", "abc"); + ctx.setAttribute(pre + "cont4.test-augment_ll6[0]", "unbounded"); + ctx.setAttribute(pre + "cont4.test-augment_ll6[1]", "8"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.cont12.leaf26", + "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.list9[0].leaf27", + "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.list9[1].leaf27", + "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.leaf28", "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.ll9[0]", "abc"); + ctx.setAttribute(pre + "cont4.test-augment_cont13.ll9[1]", "abc"); + return ctx; + } + + /** + * Creates attribute list for encoding JSON or XML with RPC YANG file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAttListRpc(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute(pre + "cont14.leaf28", "abc"); + ctx.setAttribute(pre + "list10[0].leaf29", "abc"); + ctx.setAttribute(pre + "list10[1].leaf29", "abc"); + ctx.setAttribute(pre + "leaf30", "abc"); + ctx.setAttribute(pre + "ll10[0]", "abc"); + ctx.setAttribute(pre + "ll10[1]", "abc"); + ctx.setAttribute(pre + "cont15.leaf31", "abc"); + ctx.setAttribute(pre + "cont13.list9[0].leaf27", "abc"); + ctx.setAttribute(pre + "cont13.list9[1].leaf27", "abc"); + ctx.setAttribute(pre + "cont13.leaf28", "abc"); + ctx.setAttribute(pre + "cont13.ll9[0]", "abc"); + ctx.setAttribute(pre + "cont13.ll9[1]", "abc"); + return ctx; + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * identity-ref YANG file. + * + * @param ctx service logic context + * @param pre prefix + */ + private void verifyAttList(SvcLogicContext ctx, String pre) { + String pre1 = pre + "con1.interfaces."; + assertThat(ctx.getAttribute(pre + "con1.interface"), is( + "identity-types:physical")); + assertThat(ctx.getAttribute(pre + "con1.interface"), is( + "identity-types:physical")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].iden"), is("optical")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].available.ll[0]"), is( + "Giga")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].available.ll[1]"), is( + "identity-types:Loopback")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].available.ll[2]"), is( + "identity-types-second:Ethernet")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].available.leaf1"), is( + "58")); + assertThat(ctx.getAttribute(pre1 + "int-list[0].available.leaf2"), is( + "identity-types-second:iden2")); + + assertThat(ctx.getAttribute(pre1 + "int-list[1].iden"), is( + "214748364")); + assertThat(ctx.getAttribute(pre1 + "int-list[1].available.ll[0]"), is( + "Giga")); + assertThat(ctx.getAttribute(pre1 + "int-list[1].available.ll[1]"), is( + "identity-types:Loopback")); + assertThat(ctx.getAttribute(pre1 + "int-list[1].available.ll[2]"), is( + "identity-types-second:Ethernet")); + assertThat(ctx.getAttribute(pre1 + "int-list[1].available.leaf1"), is( + "8888")); + assertThat(ctx.getAttribute(pre1 + "int-list[1].available.leaf2"), is( + "identity-types-second:iden2")); + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * container, grouping and augmented file. + * + * @param ctx service logic context + * @param pre prefix + */ + private void verifyAttListYang(SvcLogicContext ctx, String pre) { + assertThat(ctx.getAttribute(pre + "cont3.leaf10"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].leaf1"), is("true")); + assertThat(ctx.getAttribute(pre + "list1[0].leaf2"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].leaf3"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].ll1[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].ll1[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].ll2[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].ll2[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].cont4.leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].list4[0].leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].list4[1].leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].list5[0].leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[0].list5[1].leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].leaf1"), is("true")); + assertThat(ctx.getAttribute(pre + "list1[1].leaf2"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].leaf3"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].ll1[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].ll1[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].ll2[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].ll2[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].cont4.leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].list4[0].leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].list4[1].leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].list5[0].leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list1[1].list5[1].leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "list2[0].leaf4"), is("abc")); + assertThat(ctx.getAttribute(pre + "list2[1].leaf4"), is("abc")); + assertThat(ctx.getAttribute(pre + "leaf5"), is("abc")); + assertThat(ctx.getAttribute(pre + "leaf6"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll3[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll3[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll4[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll4[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.leaf10"), is( "abc")); + assertThat(ctx.getAttribute(pre + "list6[0].leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "list6[1].leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "leaf12"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll5[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll5[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont5.leaf13"), + is("true")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_list7[0].leaf14"), + is("test")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_list7[1].leaf14"), + is("create")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_leaf15"), + is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_ll6[0]"), + is("unbounded")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_ll6[1]"), + is("8")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13" + + ".cont12.leaf26"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13.list9[0]" + + ".leaf27"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13.list9[1]" + + ".leaf27"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13.leaf28"), + is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13.ll9[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "cont4.test-augment_cont13.ll9[1]"), + is("abc")); + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * RPC YANG file. + * + * @param ctx service logic context + * @param pre prefix + */ + private void verifyAttListRpc(SvcLogicContext ctx, String pre) { + assertThat(ctx.getAttribute(pre + "cont16.leaf32"), is("abc")); + assertThat(ctx.getAttribute(pre + "list11[0].leaf33"), is("abc")); + assertThat(ctx.getAttribute(pre + "list11[1].leaf33"), is("abc")); + assertThat(ctx.getAttribute(pre + "leaf34"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll11[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "ll11[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont17.leaf35"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.cont12.leaf26"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.list9[0].leaf27"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.list9[1].leaf27"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.ll9[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.ll9[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "cont13.leaf28"), is("abc")); + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * ANYXML YANG file. + * + * @param ctx service logic context + */ + private void verifyOutputOfAnyXml(SvcLogicContext ctx) { + System.out.println(ctx.getAttribute("pp.status.eventType")); + assertThat(ctx.getAttribute("pp.status.eventType"), is( + "EVENT_COMPONENT_EXECUTED")); + assertThat(ctx.getAttribute("pp.actionIdentifiers.blueprintName"), + is("golden")); + assertThat(ctx.getAttribute("pp.actionIdentifiers.mode"), + is("sync")); + assertThat(ctx.getAttribute("pp.stepData.name"), + is("resource-assignment")); + assertThat(ctx.getAttribute("pp.status.message"), + is("success")); + assertThat(ctx.getAttribute("pp.commonHeader.originatorId"), + is("System")); + assertThat(ctx.getAttribute("pp.status.code"), + is("200")); + assertThat(ctx.getAttribute("pp.commonHeader.requestId"), + is("1234")); + assertThat(ctx.getAttribute("pp.commonHeader.subRequestId"), + is("1234-12234")); + assertThat(ctx.getAttribute("pp.commonHeader.timestamp"), + is("2019-05-18T23:42:41.658Z")); + assertThat(ctx.getAttribute("pp.status.timestamp"), + is("2019-05-18T23:42:41.950Z")); + assertThat(ctx.getAttribute("pp.actionIdentifiers.blueprintV" + + "ersion"), is("1.0.0")); + assertThat(ctx.getAttribute("pp.actionIdentifiers.actionName"), + is("resource-assignment")); + assertThat(ctx.getAttribute("pp.payload.resource-assignment-resp" + + "onse.meshed-template.vf-module-1"), + is("<interface>\n <description>This i" + + "s the Virtual Firewall entity</description>\n" + + " <vfw>10.0.101.20/24</vfw>\n" + + "</interface>")); + assertThat(ctx.getAttribute("pp.actionIdentifiers.actionName"), + is("resource-assignment")); + } + + + /** + * Captures the data format messages by mocking it, which can be used in + * testing the value. + * + * @param <String> capturing data format + */ + public class DfCaptor<String> implements Answer { + + private String result; + + /** + * Returns the captured data format message. + * + * @return data format message. + */ + public String getResult() { + return result; + } + + @Override + public String answer(InvocationOnMock invocationOnMock) + throws Throwable { + result = (String) invocationOnMock.callRealMethod(); + return result; + } + } + +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatUtilsTest.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatUtilsTest.java new file mode 100644 index 000000000..c1bb71985 --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/DataFormatUtilsTest.java @@ -0,0 +1,631 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +/** + * Unit test case utilities for data format serializer and restconf api call + * node. + */ +public final class DataFormatUtilsTest { + + static final String ENCODE_TO_JSON_ID_COMMON = "\n \"interfaces\"" + + ": " + + "{\n" + + " \"int-list\": [\n" + + " {\n" + + " \"iden\": \"optical\",\n" + + " \"available\": {\n" + + " \"ll\": [\n" + + " \"Giga\",\n" + + " \"identity-types:Loopback\",\n" + + " \"identity-types-second:Ethernet" + + "\"\n" + + " ],\n" + + " \"leaf1\": \"58\",\n" + + " \"leaf2\": \"identity-types-second:iden" + + "2\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"iden\": \"214748364\",\n" + + " \"available\": {\n" + + " \"ll\": [\n" + + " \"Giga\",\n" + + " \"identity-types:Loopback\",\n" + + " \"identity-types-second:Ethernet" + + "\"\n" + + " ],\n" + + " \"leaf1\": \"8888\",\n" + + " \"leaf2\": \"identity-types-second:ide" + + "n2\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"interface\": \"identity-types:physical\"\n" + + " }"; + + static final String ENCODE_TO_JSON_ID = "{\n" + + " \"identity-test:con1\": {" + ENCODE_TO_JSON_ID_COMMON + + ",\n" + + " \"identity-test:l\": \"abc\"\n" + + "}"; + + static final String ENCODE_TO_ANYXML = "{\n" + + " \"actionIdentifiers\": {\n" + + " \"mode\": \"sync\",\n" + + " \"blueprintName\": \"baseconfiguration\",\n" + + " \"blueprintVersion\": \"1.0.0\",\n" + + " \"actionName\": \"assign-activate\"\n" + + " },\n" + + " \"payload\": {\n" + + " \"template-prefix\": \"vDNS-test\",\n" + + " \"resource-assignment-request\": {\n" + + " \"resource-assignment-properties\": {\n" + + " \"service-instance-id\": \"1234\",\n" + + " \"vnf-id\": \"3526\",\n" + + " \"customer-name\": \"htipl\",\n" + + " \"subscriber-name\": \"huawei\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"commonHeader\": {\n" + + " \"subRequestId\": \"sub-123456-1000\",\n" + + " \"requestId\": \"123456-1000\",\n" + + " \"originatorId\": \"SDNC_DG\"\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_JSON_ID_PUT = "{\n" + + " \"identity-test:test\": {\n" + + " \"con1\": {" + addSpace(ENCODE_TO_JSON_ID_COMMON, 4) + + ",\n" + + " \"l\": \"abc\"\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_XML_ID_COMMON = "\n <interfaces>\n" + + " <int-list>\n" + + " <iden>optical</iden>\n" + + " <available>\n" + + " <ll>Giga</ll>\n" + + " <ll xmlns:yangid=\"identity:list:ns:test:json:se" + + "r\">yangid:Loopback</ll>\n" + + " <ll xmlns:yangid=\"identity:list:second:ns:test" + + ":json:ser\">yangid:Ethernet</ll>\n" + + " <leaf1>58</leaf1>\n" + + " <leaf2 xmlns:yangid=\"identity:list:second:ns:t" + + "est:json:ser\">yangid:iden2</leaf2>\n" + + " </available>\n" + + " </int-list>\n" + + " <int-list>\n" + + " <iden>214748364</iden>\n" + + " <available>\n" + + " <ll>Giga</ll>\n" + + " <ll xmlns:yangid=\"identity:list:ns:test:json:s" + + "er\">yangid:Loopback</ll>\n" + + " <ll xmlns:yangid=\"identity:list:second:ns:test" + + ":json:ser\">yangid:Ethernet</ll>\n" + + " <leaf1>8888</leaf1>\n" + + " <leaf2 xmlns:yangid=\"identity:list:second:ns:t" + + "est:json:ser\">yangid:iden2</leaf2>\n" + + " </available>\n" + + " </int-list>\n" + + " </interfaces>\n" + + " <interface xmlns:yangid=\"identity:list:ns:test:json:ser\">" + + "yangid:physical</interface>"; + + static final String ENCODE_TO_XML_ID = "<?xml version=\"1.0\" encoding=" + + "\"UTF-8\" standalone=\"no\"?>\n" + + "<con1 xmlns=\"identity:ns:test:json:ser\">" + + ENCODE_TO_XML_ID_COMMON + "\n</con1>\n"; + + static final String ENCODE_TO_XML_ID_PUT = "<?xml version=\"1.0\" enco" + + "ding=\"UTF-8\" standalone=\"no\"?>\n" + + "<test xmlns=\"identity:ns:test:json:ser\">\n" + + " <con1>" + addSpace(ENCODE_TO_XML_ID_COMMON, 4) + + "\n </con1>\n" + + "</test>\n"; + + static final String ENCODE_TO_JSON_YANG_COMMON = "\n " + + "\"test-augment:ll6\": [\n" + + " \"unbounded\",\n" + + " \"8\"\n" + + " ],\n" + + " \"test-augment:cont13\": {\n" + + " \"ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"list9\": [\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"leaf28\": \"abc\",\n" + + " \"cont12\": {\n" + + " \"leaf26\": \"abc\"\n" + + " }\n" + + " },\n" + + " \"test-augment:list7\": [\n" + + " {\n" + + " \"leaf14\": \"test\"\n" + + " },\n" + + " {\n" + + " \"leaf14\": \"create\"\n" + + " }\n" + + " ],\n" + + " \"test-augment:leaf15\": \"abc\",\n" + + " \"test-augment:cont5\": {\n" + + " \"leaf13\": \"true\"\n" + + " }"; + + static final String ENCODE_TO_JSON_YANG_AUG_POST = "{\n" + + " \"test-yang:leaf10\": \"abc\"," + + ENCODE_TO_JSON_YANG_COMMON + "\n}"; + + static final String ENCODE_TO_JSON_YANG = "{\n" + + " \"test-yang:cont2\": {\n" + + " \"list1\": [\n" + + " {\n" + + " \"ll1\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"leaf1\": \"true\",\n" + + " \"ll2\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"list5\": [\n" + + " {\n" + + " \"leaf9\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf9\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"leaf3\": \"abc\",\n" + + " \"leaf2\": \"abc\",\n" + + " \"list4\": [\n" + + " {\n" + + " \"leaf8\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf8\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"cont4\": {\n" + + " \"leaf11\": \"abc\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"ll1\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"leaf1\": \"true\",\n" + + " \"ll2\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"leaf3\": \"abc\",\n" + + " \"list5\": [\n" + + " {\n" + + " \"leaf9\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf9\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"list4\": [\n" + + " {\n" + + " \"leaf8\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf8\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"leaf2\": \"abc\",\n" + + " \"cont4\": {\n" + + " \"leaf11\": \"abc\"\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"ll3\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"ll5\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"cont4\": {\n" + + " \"leaf10\": \"abc\"," + + addSpace(ENCODE_TO_JSON_YANG_COMMON, 8) + "\n" + + " },\n" + + " \"ll4\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"cont3\": {\n" + + " \"leaf10\": \"abc\"\n" + + " },\n" + + " \"leaf5\": \"abc\",\n" + + " \"list2\": [\n" + + " {\n" + + " \"leaf4\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf4\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"leaf12\": \"abc\",\n" + + " \"leaf6\": \"abc\",\n" + + " \"list6\": [\n" + + " {\n" + + " \"leaf11\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf11\": \"abc\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_JSON_YANG_PUT = "{\n" + + " \"test-yang:cont4\": {" + addSpace( + ENCODE_TO_JSON_YANG_COMMON, 4) + ",\n" + + " \"leaf10\": \"abc\"\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_XML_YANG_COMMON = "\n" + + "<ll6 xmlns=\"urn:opendaylight:params:xml:ns:yang:aug" + + "ment\">unbounded</ll6>\n" + + "<ll6 xmlns=\"urn:opendaylight:params:xml:ns:yang:aug" + + "ment\">8</ll6>\n" + + "<cont13 xmlns=\"urn:opendaylight:params:xml:ns:yang:" + + "augment\">\n" + + " <ll9>abc</ll9>\n" + + " <ll9>abc</ll9>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <leaf28>abc</leaf28>\n" + + " <cont12>\n" + + " <leaf26>abc</leaf26>\n" + + " </cont12>\n" + + "</cont13>\n" + + "<list7 xmlns=\"urn:opendaylight:params:xml:ns:yang:a" + + "ugment\">\n" + + " <leaf14>test</leaf14>\n" + + "</list7>\n" + + "<list7 xmlns=\"urn:opendaylight:params:xml:ns:yang:a" + + "ugment\">\n" + + " <leaf14>create</leaf14>\n" + + "</list7>\n" + + "<leaf15 xmlns=\"urn:opendaylight:params:xml:ns:yang:" + + "augment\">abc</leaf15>\n" + + "<cont5 xmlns=\"urn:opendaylight:params:xml:ns:yang:a" + + "ugment\">\n" + + " <leaf13>true</leaf13>\n" + + "</cont5>"; + + static final String ENCODE_TO_XML_YANG_AUG_POST = "<?xml version=\"1.0\"" + + " encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<leaf10 xmlns=\"urn:opendaylight:params:xml:ns:yang:test\">abc" + + "</leaf10>" + + ENCODE_TO_XML_YANG_COMMON + "\n"; + + static final String ENCODE_TO_XML_YANG_PUT = "<?xml version=\"1.0\" enc" + + "oding=\"UTF-8\" standalone=\"no\"?>\n" + + "<cont4 xmlns=\"urn:opendaylight:params:xml:ns:yang:test\">\n" + + " <leaf10>abc</leaf10>" + + addSpace(ENCODE_TO_XML_YANG_COMMON, 4) + "\n</cont4>\n"; + + static final String ENCODE_TO_XML_YANG = "<?xml version=\"1.0\" encoding" + + "=\"UTF-8\" standalone=\"no\"?>\n" + + "<cont2 xmlns=\"urn:opendaylight:params:xml:ns:yang:test\">\n" + + " <list1>\n" + + " <ll1>abc</ll1>\n" + + " <ll1>abc</ll1>\n" + + " <leaf1>true</leaf1>\n" + + " <ll2>abc</ll2>\n" + + " <ll2>abc</ll2>\n" + + " <list5>\n" + + " <leaf9>abc</leaf9>\n" + + " </list5>\n" + + " <list5>\n" + + " <leaf9>abc</leaf9>\n" + + " </list5>\n" + + " <leaf3>abc</leaf3>\n" + + " <leaf2>abc</leaf2>\n" + + " <list4>\n" + + " <leaf8>abc</leaf8>\n" + + " </list4>\n" + + " <list4>\n" + + " <leaf8>abc</leaf8>\n" + + " </list4>\n" + + " <cont4>\n" + + " <leaf11>abc</leaf11>\n" + + " </cont4>\n" + + " </list1>\n" + + " <list1>\n" + + " <ll1>abc</ll1>\n" + + " <ll1>abc</ll1>\n" + + " <leaf1>true</leaf1>\n" + + " <ll2>abc</ll2>\n" + + " <ll2>abc</ll2>\n" + + " <leaf3>abc</leaf3>\n" + + " <list5>\n" + + " <leaf9>abc</leaf9>\n" + + " </list5>\n" + + " <list5>\n" + + " <leaf9>abc</leaf9>\n" + + " </list5>\n" + + " <list4>\n" + + " <leaf8>abc</leaf8>\n" + + " </list4>\n" + + " <list4>\n" + + " <leaf8>abc</leaf8>\n" + + " </list4>\n" + + " <leaf2>abc</leaf2>\n" + + " <cont4>\n" + + " <leaf11>abc</leaf11>\n" + + " </cont4>\n" + + " </list1>\n" + + " <ll3>abc</ll3>\n" + + " <ll3>abc</ll3>\n" + + " <ll5>abc</ll5>\n" + + " <ll5>abc</ll5>\n" + + " <cont4>\n" + + " <leaf10>abc</leaf10>"+ + addSpace(ENCODE_TO_XML_YANG_COMMON, 8) + "\n" + + " </cont4>\n" + + " <ll4>abc</ll4>\n" + + " <ll4>abc</ll4>\n" + + " <cont3>\n" + + " <leaf10>abc</leaf10>\n" + + " </cont3>\n" + + " <leaf5>abc</leaf5>\n" + + " <list2>\n" + + " <leaf4>abc</leaf4>\n" + + " </list2>\n" + + " <list2>\n" + + " <leaf4>abc</leaf4>\n" + + " </list2>\n" + + " <leaf12>abc</leaf12>\n" + + " <leaf6>abc</leaf6>\n" + + " <list6>\n" + + " <leaf11>abc</leaf11>\n" + + " </list6>\n" + + " <list6>\n" + + " <leaf11>abc</leaf11>\n" + + " </list6>\n" + + "</cont2>\n"; + + static final String ENCODE_TO_JSON_RPC = "{\n" + + " \"test-yang:input\": {\n" + + " \"leaf30\": \"abc\",\n" + + " \"list10\": [\n" + + " {\n" + + " \"leaf29\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf29\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"cont15\": {\n" + + " \"leaf31\": \"abc\"\n" + + " },\n" + + " \"cont14\": {\n" + + " \"leaf28\": \"abc\"\n" + + " },\n" + + " \"cont13\": {\n" + + " \"list9\": [\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"leaf28\": \"abc\"\n" + + " },\n" + + " \"ll10\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ]\n" + + " }\n" + + "}"; + + static final String DECODE_FROM_JSON_RPC = "{\n" + + " \"test-yang:output\": {\n" + + " \"cont16\": {\n" + + " \"leaf32\": \"abc\"\n" + + " },\n" + + " \"list11\": [\n" + + " {\n" + + " \"leaf33\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf33\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"leaf34\": \"abc\",\n" + + " \"ll11\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"cont17\": {\n" + + " \"leaf35\": \"abc\"\n" + + " },\n" + + " \"cont13\": {\n" + + " \"cont12\": {\n" + + " \"leaf26\": \"abc\"\n" + + " },\n" + + " \"list9\": [\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"leaf27\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"leaf28\": \"abc\"\n" + + " }\n" + + " }\n" + + "}"; + + static final String DECODE_ANYXML_RESPONSE = "{\n" + + " \"commonHeader\": {\n" + + " \"timestamp\": \"2019-05-18T23:42:41.658Z\",\n" + + " \"originatorId\": \"System\",\n" + + " \"requestId\": \"1234\",\n" + + " \"subRequestId\": \"1234-12234\",\n" + + " \"flags\": null\n" + + " },\n" + + " \"actionIdentifiers\": {\n" + + " \"blueprintName\": \"golden\",\n" + + " \"blueprintVersion\": \"1.0.0\",\n" + + " \"actionName\": \"resource-assignment\",\n" + + " \"mode\": \"sync\"\n" + + " },\n" + + " \"status\": {\n" + + " \"code\": 200,\n" + + " \"eventType\": \"EVENT_COMPONENT_EXECUTED\",\n" + + " \"timestamp\": \"2019-05-18T23:42:41.950Z\",\n" + + " \"errorMessage\": null,\n" + + " \"message\": \"success\"\n" + + " },\n" + + " \"payload\": {\n" + + " \"resource-assignment-response\": {\n" + + " \"meshed-template\": {\n" + + " \"vf-module-1\": \"<interface>\\n " + + " <description>This is the Virtual Firewall entity</" + + "description>\\n <vfw>10.0.101.20/24</vfw>\\n</interface>\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"stepData\": {\n" + + " \"name\": \"resource-assignment\",\n" + + " \"properties\": {\n" + + " \"resource-assignment-params\": null,\n" + + " \"status\": null\n" + + " }\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_XML_RPC = "<?xml version=\"1.0\" encoding" + + "=\"UTF-8\" standalone=\"no\"?>\n" + + "<input xmlns=\"urn:opendaylight:params:xml:ns:yang:test\">\n" + + " <leaf30>abc</leaf30>\n" + + " <list10>\n" + + " <leaf29>abc</leaf29>\n" + + " </list10>\n" + + " <list10>\n" + + " <leaf29>abc</leaf29>\n" + + " </list10>\n" + + " <cont15>\n" + + " <leaf31>abc</leaf31>\n" + + " </cont15>\n" + + " <cont14>\n" + + " <leaf28>abc</leaf28>\n" + + " </cont14>\n" + + " <cont13>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <ll9>abc</ll9>\n" + + " <ll9>abc</ll9>\n" + + " <leaf28>abc</leaf28>\n" + + " </cont13>\n" + + " <ll10>abc</ll10>\n" + + " <ll10>abc</ll10>\n" + + "</input>\n"; + + static final String DECODE_FROM_XML_RPC = "<?xml version=\"1.0\" encodi" + + "ng=\"UTF-8\" standalone=\"no\"?>\n" + + "<output xmlns=\"urn:opendaylight:params:xml:ns:yang:test\">\n" + + " <cont16>\n" + + " <leaf32>abc</leaf32>\n" + + " </cont16>\n" + + " <list11>\n" + + " <leaf33>abc</leaf33>\n" + + " </list11>\n" + + " <list11>\n" + + " <leaf33>abc</leaf33>\n" + + " </list11>\n" + + " <leaf34>abc</leaf34>\n" + + " <ll11>abc</ll11>\n" + + " <ll11>abc</ll11>\n" + + " <cont17>\n" + + " <leaf35>abc</leaf35>\n" + + " </cont17>\n" + + " <cont13>\n" + + " <cont12>\n" + + " <leaf26>abc</leaf26>\n" + + " </cont12>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <list9>\n" + + " <leaf27>abc</leaf27>\n" + + " </list9>\n" + + " <ll9>abc</ll9>\n" + + " <ll9>abc</ll9>\n" + + " <leaf28>abc</leaf28>\n" + + " </cont13>\n" + + "</output>"; + + /** + * Adds the specified number of space required for a req in each line. + * + * @param req request message + * @param i number of space + * @return space appended string + */ + public static String addSpace(String req, int i) { + StringBuilder space = new StringBuilder(); + for (int sp = 0; sp < i; sp++) { + space = space.append(" "); + } + return req.replaceAll("\n", "\n" + space.toString()); + } +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationTest.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationTest.java new file mode 100644 index 000000000..1109d426c --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationTest.java @@ -0,0 +1,762 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.restapicall.HttpResponse; +import org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode; +import org.onap.ccsdk.sli.plugins.restconfapicall.RestconfApiCallNode; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.DECODE_FROM_JSON_RPC_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.DECODE_FROM_XML_RPC_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_JSON_RPC_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_JSON_WITH_AUG_PATH; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_JSON_YANG_AUG_POST_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_JSON_YANG_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_JSON_YANG_PUT_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_XML_RPC_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_XML_YANG_AUG_POST_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_XML_YANG_ID; +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.IdentifierValidationUtilsTest.ENCODE_TO_XML_YANG_PUT_ID; + +/** + * Unit test cases for identifier validation test. + */ +public class IdentifierValidationTest { + + private Map<String, String> p; + + private RestconfApiCallNode restconf; + + private RestapiCallNode restApi; + + private DfCaptor dfCaptor; + + /** + * Sets up the pre-requisite for each test case. + * + * @throws SvcLogicException when test case fails + */ + @Before + public void setUp() throws SvcLogicException { + p = new HashMap<>(); + p.put("restapiUser", "user1"); + p.put("restapiPassword", "abc123"); + p.put("responsePrefix", "response"); + p.put("skipSending", "true"); + restApi = new RestapiCallNode(); + restconf = mock(RestconfApiCallNode.class); + dfCaptor = new DfCaptor(); + createMethodMocks(); + } + + /** + * Creates method mocks using mockito for RestconfApiCallNode class. + * + * @throws SvcLogicException when test case fails + */ + private void createMethodMocks() throws SvcLogicException { + doReturn(restApi).when(restconf).getRestapiCallNode(); + doCallRealMethod().when(restconf).sendRequest( + any(Map.class), any(SvcLogicContext.class)); + doCallRealMethod().when(restconf).sendRequest( + any(Map.class), any(SvcLogicContext.class), any(Integer.class)); + doAnswer(dfCaptor).when(restconf).serializeRequest( + any(Map.class), any(YangParameters.class), any(String.class), + any(InstanceIdentifierContext.class)); + doAnswer(dfCaptor).when(restconf).updateReq( + any(String.class), any(YangParameters.class), + any(InstanceIdentifierContext.class)); + } + + /** + * Creates mock using mockito with input data for decoding. + * + * @param decodeData input data + * @throws SvcLogicException when test case fails + */ + private void createMockForDecode(String decodeData) + throws SvcLogicException { + doReturn(decodeData).when(restconf).getResponse( + any(SvcLogicContext.class), any(YangParameters.class), + any(String.class), any(HttpResponse.class)); + doCallRealMethod().when(restconf).serializeResponse( + any(YangParameters.class), any(String.class), any(String.class), + any(InstanceIdentifierContext.class)); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYang() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_" + + "of_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operati" + + "ons/test_name_of_the_module:name_of_the_cont1"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_ID)); + } + + /** + * Verifies encoding of parameters with augment in the URL. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYangWithAugUrl() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_" + + "of_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operati" + + "ons/test_name_of_the_module:name_of_the_cont1/name_of_t" + + "he_cont2/name_of_the_cont4/test_augment_1_for_module:na" + + "me_of_the_cont5"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_WITH_AUG_PATH)); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment for put operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYangWithPut() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_of_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test_name_of_the_module:name_of" + + "_the_cont1/name_of_the_cont2/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_PUT_ID)); + } + + /** + * Verifies encoding of parameters to JSON data format with containers, + * grouping and augment for patch operation-type. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonYangWithPatch() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_o" + + "f_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "patch"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test_name_of_the_module:name_of_" + + "the_cont1/name_of_the_cont2/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_PUT_ID)); + } + + /** + * Verifies encoding of parameters to JSON data format with augment as + * root child. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToJsonWithAugAsRootChild() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_of_" + + "the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test_name_of_the_module:name_of_" + + "the_cont1/name_of_the_cont2/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_YANG_AUG_POST_ID)); + } + + /** + * Verifies decoding of parameters from JSON data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToJsonYang() throws SvcLogicException { + createMockForDecode(ENCODE_TO_JSON_YANG_ID); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "test_name_of_the_module_name_of_the_cont1.name_" + + "of_the_cont2."; + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test_name_of_the_module:name" + + "_of_the_cont1"); + restconf.sendRequest(p, ctx); + verifyAttListYang(ctx, pre); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYang() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_of" + + "_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operations/" + + "test_name_of_the_module:name_of_the_cont1"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_ID)); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment for put operation-type + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYangWithPut() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_" + + "of_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operations/" + + "test_name_of_the_module:name_of_the_cont1/name_of_the_cont2" + + "/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_PUT_ID)); + } + + /** + * Verifies encoding of parameters to XML data format with containers, + * grouping and augment for patch operation-type + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlYangWithPatch() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_of" + + "_the_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "put"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operation" + + "s/test_name_of_the_module:name_of_the_cont1/name_of_the_c" + + "ont2/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_PUT_ID)); + } + + /** + * Verifies encoding of parameters to XML data format with augment as + * root child. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void encodeToXmlWithAugAsRootChild() throws SvcLogicException { + String pre = "test_name_of_the_module_name_of_the_cont1.name_of_the" + + "_cont2."; + SvcLogicContext ctx = createAttListYang(pre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operations/" + + "test_name_of_the_module:name_of_the_cont1/name_of_the_cont2" + + "/name_of_the_cont4"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_YANG_AUG_POST_ID)); + } + + /** + * Verifies decoding of parameters from XML data format with containers, + * grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void decodeToXmlYang() throws SvcLogicException { + createMockForDecode(ENCODE_TO_XML_YANG_ID); + SvcLogicContext ctx = new SvcLogicContext(); + String pre = "test_name_of_the_module_name_of_the_cont1.name_of_" + + "the_cont2."; + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "get"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operation" + + "s/test_name_of_the_module:name_of_the_cont1"); + restconf.sendRequest(p, ctx); + verifyAttListYang(ctx, pre); + } + + /** + * Verifies encoding of and decoding from, JSON respectively for data + * format with containers, grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void codecToJsonRpc() throws SvcLogicException { + createMockForDecode(DECODE_FROM_JSON_RPC_ID); + String inPre = "test_name_of_the_module_name_of_the_create-sfc.input."; + String outPre = "test_name_of_the_module_name_of_the_create-sfc" + + ".output."; + SvcLogicContext ctx = createAttListRpc(inPre); + p.put("dirPath", "src/test/resources"); + p.put("format", "json"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman.com/restconf/operations" + + "/test_name_of_the_module:name_of_the_create-sfc"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_JSON_RPC_ID)); + verifyAttListRpc(ctx, outPre); + } + + /** + * Verifies encoding of and decoding from, XML respectively for data + * format with containers, grouping and augment. + * + * @throws SvcLogicException when test case fails + */ + @Test + public void codecToXmlRpc() throws SvcLogicException { + createMockForDecode(DECODE_FROM_XML_RPC_ID); + String inPre = "test_name_of_the_module_name_of_the_create-sfc.input."; + String outPre = "test_name_of_the_module_name_of_the_create-sfc.output."; + SvcLogicContext ctx = createAttListRpc(inPre); + p.put("dirPath", "src/test/resources"); + p.put("format", "xml"); + p.put("httpMethod", "post"); + p.put("restapiUrl", "http://echo.getpostman" + + ".com/restconf/operations/test_name_of_the_module" + + ":name_of_the_create-sfc"); + restconf.sendRequest(p, ctx); + assertThat(dfCaptor.getResult(), is(ENCODE_TO_XML_RPC_ID)); + verifyAttListRpc(ctx, outPre); + } + + /** + * Creates attribute list for encoding JSON or XML with container, + * grouping and augmented YANG file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAttListYang(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute(pre + "name_of_the_cont3.name_of_the_leaf" + + "10", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_leaf1" + + "", "true"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_leaf2" + + "", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_leaf3" + + "", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "ll1[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "ll1[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "ll2[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "ll2[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "cont4.name_of_the_leaf11", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "list4[0].name_of_the_leaf8", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "list4[1].name_of_the_leaf8", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "list5[0].name_of_the_leaf9", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[0].name_of_the_" + + "list5[1].name_of_the_leaf9", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "leaf1", "true"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "leaf2", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "leaf3", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "ll1[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "ll1[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "ll2[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "ll2[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "cont4.name_of_the_leaf11", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "list4[0].name_of_the_leaf8", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "list4[1].name_of_the_leaf8", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "list5[0].name_of_the_leaf9", "abc"); + ctx.setAttribute(pre + "name_of_the_list1[1].name_of_the_" + + "list5[1].name_of_the_leaf9", "abc"); + ctx.setAttribute(pre + "name_of_the_list2[0].name_of_the_" + + "leaf4", "abc"); + ctx.setAttribute(pre + "name_of_the_list2[1].name_of_the_" + + "leaf4", "abc"); + ctx.setAttribute(pre + "name_of_the_leaf5", "abc"); + ctx.setAttribute(pre + "name_of_the_leaf6", "abc"); + ctx.setAttribute(pre + "name_of_the_ll3[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_ll3[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_ll4[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_ll4[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.name_of_the_leaf10", + "abc"); + ctx.setAttribute(pre + "name_of_the_list6[0].name_of_the_leaf11", + "abc"); + ctx.setAttribute(pre + "name_of_the_list6[1].name_of_the_leaf11", + "abc"); + ctx.setAttribute(pre + "name_of_the_leaf12", "abc"); + ctx.setAttribute(pre + "name_of_the_ll5[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_ll5[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_cont5.name_of_the_leaf13", + "true"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_list7[0].name_of_the" + + "_leaf14", "test"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_list7[1].name_of_the" + + "_leaf14", "create"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_leaf15", "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_ll6[0]", + "unbounded"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_ll6[1]", "8"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_cont13.name_of_the_" + + "cont12.name_of_the_leaf26", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for_" + + "module_name_of_the_cont13.name_of_the_" + + "list9[0].name_of_the_leaf27", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_cont13.name_of_the_" + + "list9[1].name_of_the_leaf27", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_cont13.name_of_the_" + + "leaf28", "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_cont13.name_of_the_" + + "ll9[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_cont4.test_augment_1_for" + + "_module_name_of_the_cont13.name_of_the_" + + "ll9[1]", "abc"); + return ctx; + } + + /** + * Creates attribute list for encoding JSON or XML with RPC YANG file. + * + * @param pre prefix + * @return service logic context + */ + private SvcLogicContext createAttListRpc(String pre) { + SvcLogicContext ctx = new SvcLogicContext(); + ctx.setAttribute(pre + "name_of_the_cont14.name_of_the_leaf28", + "abc"); + ctx.setAttribute(pre + "name_of_the_list10[0].name_of_the_leaf29", + "abc"); + ctx.setAttribute(pre + "name_of_the_list10[1].name_of_the_leaf29", + "abc"); + ctx.setAttribute(pre + "name_of_the_leaf30", "abc"); + ctx.setAttribute(pre + "name_of_the_ll10[0]", "abc"); + ctx.setAttribute(pre + "name_of_the_ll10[1]", "abc"); + ctx.setAttribute(pre + "name_of_the_cont15.name_of_the_leaf31", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont13.name_of_the_list9[0]" + + ".name_of_the_leaf27", "abc"); + ctx.setAttribute(pre + "name_of_the_cont13.name_of_the_list9[1]" + + ".name_of_the_leaf27", "abc"); + ctx.setAttribute(pre + "name_of_the_cont13.name_of_the_leaf28", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont13.name_of_the_ll9[0]", + "abc"); + ctx.setAttribute(pre + "name_of_the_cont13.name_of_the_ll9[1]", + "abc"); + return ctx; + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * container, grouping and augmented file. + * + * @param ctx service logic context + * @param pre prefix + */ + private void verifyAttListYang(SvcLogicContext ctx, String pre) { + assertThat(ctx.getAttribute(pre + "name_of_the_cont3.name_of" + + "_the_leaf10"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_leaf1"), is("true")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_leaf2"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_leaf3"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_ll1[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_ll1[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_ll2[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_ll2[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name" + + "_of_the_cont4.name_of_the_leaf11"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name_of" + + "_the_list4[0].name_of_the_leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name_of" + + "_the_list4[1].name_of_the_leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name_of" + + "_the_list5[0].name_of_the_leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[0].name_of" + + "_the_list5[1].name_of_the_leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_leaf1"), is("true")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_leaf2"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_leaf3"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_ll1[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_ll1[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_ll2[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_ll2[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_cont4.name_of_the_leaf11"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_list4[0].name_of_the_leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_list4[1].name_of_the_leaf8"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_list5[0].name_of_the_leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list1[1].name_of" + + "_the_list5[1].name_of_the_leaf9"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list2[0].name_of" + + "_the_leaf4"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list2[1].name_of" + + "_the_leaf4"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_leaf5"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_leaf6"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll3[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll3[1]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll4[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll4[1]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.name_of" + + "_the_leaf10"), is( "abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list6[0].name_of" + + "_the_leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list6[1].name_of" + + "_the_leaf11"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_leaf12"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll5[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll5[1]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont5.name_of_the_leaf13"), + is("true")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_list7[0].name_of_the_leaf14"), + is("test")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_list7[1].name_of_the_leaf14"), + is("create")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_leaf15"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_ll6[0]"), + is("unbounded")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_ll6[1]"), + is("8")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13" + + ".name_of_the_cont12.name_of_" + + "the_leaf26"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13.name_of_the_list9[0]" + + ".name_of_the_leaf27"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13.name_of_the_list9[1]" + + ".name_of_the_leaf27"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13.name_of_the_leaf28"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13.name_of_the_ll9[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont4.test_" + + "augment_1_for_module_name_of_" + + "the_cont13.name_of_the_ll9[1]"), + is("abc")); + } + + /** + * Verifies the attribute list for decoding from JSON or XML with + * RPC YANG file. + * + * @param ctx service logic context + * @param pre prefix + */ + private void verifyAttListRpc(SvcLogicContext ctx, String pre) { + assertThat(ctx.getAttribute(pre + "name_of_the_cont16.name_of_" + + "the_leaf32"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list11[0].name" + + "_of_the_leaf33"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_list11[1].name" + + "_of_the_leaf33"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_leaf34"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll11[0]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_ll11[1]"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont17.name_of_" + + "the_leaf35"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_cont12.name_of_the_leaf26"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_list9[0].name_of_the_leaf27"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_list9[1].name_of_the_leaf27"), + is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_ll9[0]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_ll9[1]"), is("abc")); + assertThat(ctx.getAttribute(pre + "name_of_the_cont13.name_of_" + + "the_leaf28"), is("abc")); + } + + /** + * Captures the data format messages by mocking it, which can be used in + * testing the value. + * + * @param <String> capturing data format + */ + public class DfCaptor<String> implements Answer { + + private String result; + + /** + * Returns the captured data format message. + * + * @return data format message. + */ + public String getResult() { + return result; + } + + @Override + public String answer(InvocationOnMock invocationOnMock) + throws Throwable { + result = (String) invocationOnMock.callRealMethod(); + return result; + } + } + +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationUtilsTest.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationUtilsTest.java new file mode 100644 index 000000000..a866f1c4a --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/dfserializer/IdentifierValidationUtilsTest.java @@ -0,0 +1,469 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.yangserializers.dfserializer; + +import static org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.DataFormatUtilsTest.addSpace; + +/** + * Unit test case utilities for identifier validation and restconf api + * call node. + */ +public final class IdentifierValidationUtilsTest { + + static final String ENCODE_TO_JSON_YANG_COMMON_ID = "\n " + + "\"test_augment_1_for_module:name_of_the_ll6\": [\n" + + " \"unbounded\",\n" + + " \"8\"\n" + + " ],\n" + + " \"test_augment_1_for_module:name_of_the_cont13\": {\n" + + " \"name_of_the_cont12\": {\n" + + " \"name_of_the_leaf26\": \"abc\"\n" + + " },\n" + + " \"name_of_the_ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_leaf28\": \"abc\",\n" + + " \"name_of_the_list9\": [\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"test_augment_1_for_module:name_of_the_list7\": [\n" + + " {\n" + + " \"name_of_the_leaf14\": \"test\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf14\": \"create\"\n" + + " }\n" + + " ],\n" + + " \"test_augment_1_for_module:name_of_the_leaf15\": \"abc\",\n" + + " \"test_augment_1_for_module:name_of_the_cont5\": {\n" + + " \"name_of_the_leaf13\": \"true\"\n" + + " }"; + + static final String ENCODE_TO_JSON_YANG_AUG_POST_ID = "{\n" + + " \"test_name_of_the_module:name_of_the_leaf10\": \"abc\"," + + ENCODE_TO_JSON_YANG_COMMON_ID + "\n}"; + + static final String ENCODE_TO_JSON_YANG_ID = "{\n" + + " \"test_name_of_the_module:name_of_the_cont2\": {\n" + + " \"name_of_the_ll4\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_leaf5\": \"abc\",\n" + + " \"name_of_the_list6\": [\n" + + " {\n" + + " \"name_of_the_leaf11\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf11\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_ll5\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_ll3\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_leaf6\": \"abc\",\n" + + " \"name_of_the_cont3\": {\n" + + " \"name_of_the_leaf10\": \"abc\"\n" + + " },\n" + + " \"name_of_the_list2\": [\n" + + " {\n" + + " \"name_of_the_leaf4\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf4\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_list1\": [\n" + + " {\n" + + " \"name_of_the_ll2\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_list5\": [\n" + + " {\n" + + " \"name_of_the_leaf9\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf9\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_list4\": [\n" + + " {\n" + + " \"name_of_the_leaf8\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf8\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_leaf1\": \"true\",\n" + + " \"name_of_the_leaf3\": \"abc\",\n" + + " \"name_of_the_leaf2\": \"abc\",\n" + + " \"name_of_the_cont4\": {\n" + + " \"name_of_the_leaf11\": \"abc\"\n" + + " },\n" + + " \"name_of_the_ll1\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name_of_the_ll2\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_list5\": [\n" + + " {\n" + + " \"name_of_the_leaf9\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf9\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_list4\": [\n" + + " {\n" + + " \"name_of_the_leaf8\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf8\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_leaf1\": \"true\",\n" + + " \"name_of_the_leaf3\": \"abc\",\n" + + " \"name_of_the_leaf2\": \"abc\",\n" + + " \"name_of_the_cont4\": {\n" + + " \"name_of_the_leaf11\": \"abc\"\n" + + " },\n" + + " \"name_of_the_ll1\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"name_of_the_cont4\": {\n" + + " \"name_of_the_leaf10\": \"abc\"," + + addSpace(ENCODE_TO_JSON_YANG_COMMON_ID,8) + "\n" + + " },\n" + + " \"name_of_the_leaf12\": \"abc\"\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_JSON_WITH_AUG_PATH = "{\n" + + " \"test_augment_1_for_module:name_of_the_leaf13\": \"true\"\n" + + "}"; + + static final String ENCODE_TO_JSON_YANG_PUT_ID = "{\n" + + " \"test_name_of_the_module:name_of_the_cont4\": {" + addSpace( + ENCODE_TO_JSON_YANG_COMMON_ID, 4) + ",\n" + + " \"name_of_the_leaf10\": \"abc\"\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_XML_YANG_COMMON_ID = "\n" + + "<name_of_the_ll6 xmlns=\"urn:opendaylight:params:xml:ns:yang:" + + "test:augment:name\">unbounded</name_of_the_ll6>\n" + + "<name_of_the_ll6 xmlns=\"urn:opendaylight:params:xml:ns:yang:" + + "test:augment:name\">8</name_of_the_ll6>\n" + + "<name_of_the_cont13 xmlns=\"urn:opendaylight:params:xml:ns:ya" + + "ng:test:augment:name\">\n" + + " <name_of_the_cont12>\n" + + " <name_of_the_leaf26>abc</name_of_the_leaf26>\n" + + " </name_of_the_cont12>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_leaf28>abc</name_of_the_leaf28>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + "</name_of_the_cont13>\n" + + "<name_of_the_list7 xmlns=\"urn:opendaylight:params:xml:ns:yan" + + "g:test:augment:name\">\n" + + " <name_of_the_leaf14>test</name_of_the_leaf14>\n" + + "</name_of_the_list7>\n" + + "<name_of_the_list7 xmlns=\"urn:opendaylight:params:xml:ns:yan" + + "g:test:augment:name\">\n" + + " <name_of_the_leaf14>create</name_of_the_leaf14>\n" + + "</name_of_the_list7>\n" + + "<name_of_the_leaf15 xmlns=\"urn:opendaylight:params:xml:ns:ya" + + "ng:test:augment:name\">abc</name_of_the_leaf15>\n" + + "<name_of_the_cont5 xmlns=\"urn:opendaylight:params:xml:ns:yan" + + "g:test:augment:name\">\n" + + " <name_of_the_leaf13>true</name_of_the_leaf13>\n" + + "</name_of_the_cont5>"; + + static final String ENCODE_TO_XML_YANG_AUG_POST_ID = "<?xml version=\"1" + + ".0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<name_of_the_leaf10 xmlns=\"urn:opendaylight:params:xml:ns:yan" + + "g:test:name\">abc</name_of_the_leaf10>" + + ENCODE_TO_XML_YANG_COMMON_ID + "\n"; + + static final String ENCODE_TO_XML_YANG_PUT_ID = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<name_of_the_cont4 xmlns=\"urn:opendaylight:params:xml:ns:yang" + + ":test:name\">\n" + + " <name_of_the_leaf10>abc</name_of_the_leaf10>" + + addSpace(ENCODE_TO_XML_YANG_COMMON_ID, 4) + "\n</name_of_the_co" + + "nt4>\n"; + + static final String ENCODE_TO_XML_YANG_ID= "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<name_of_the_cont2 xmlns=\"urn:opendaylight:params:xml:ns:yan" + + "g:test:name\">\n" + + " <name_of_the_ll4>abc</name_of_the_ll4>\n" + + " <name_of_the_ll4>abc</name_of_the_ll4>\n" + + " <name_of_the_leaf5>abc</name_of_the_leaf5>\n" + + " <name_of_the_list6>\n" + + " <name_of_the_leaf11>abc</name_of_the_leaf11>\n" + + " </name_of_the_list6>\n" + + " <name_of_the_list6>\n" + + " <name_of_the_leaf11>abc</name_of_the_leaf11>\n" + + " </name_of_the_list6>\n" + + " <name_of_the_ll5>abc</name_of_the_ll5>\n" + + " <name_of_the_ll5>abc</name_of_the_ll5>\n" + + " <name_of_the_ll3>abc</name_of_the_ll3>\n" + + " <name_of_the_ll3>abc</name_of_the_ll3>\n" + + " <name_of_the_leaf6>abc</name_of_the_leaf6>\n" + + " <name_of_the_cont3>\n" + + " <name_of_the_leaf10>abc</name_of_the_leaf10>\n" + + " </name_of_the_cont3>\n" + + " <name_of_the_list2>\n" + + " <name_of_the_leaf4>abc</name_of_the_leaf4>\n" + + " </name_of_the_list2>\n" + + " <name_of_the_list2>\n" + + " <name_of_the_leaf4>abc</name_of_the_leaf4>\n" + + " </name_of_the_list2>\n" + + " <name_of_the_list1>\n" + + " <name_of_the_ll2>abc</name_of_the_ll2>\n" + + " <name_of_the_ll2>abc</name_of_the_ll2>\n" + + " <name_of_the_list5>\n" + + " <name_of_the_leaf9>abc</name_of_the_leaf9>\n" + + " </name_of_the_list5>\n" + + " <name_of_the_list5>\n" + + " <name_of_the_leaf9>abc</name_of_the_leaf9>\n" + + " </name_of_the_list5>\n" + + " <name_of_the_list4>\n" + + " <name_of_the_leaf8>abc</name_of_the_leaf8>\n" + + " </name_of_the_list4>\n" + + " <name_of_the_list4>\n" + + " <name_of_the_leaf8>abc</name_of_the_leaf8>\n" + + " </name_of_the_list4>\n" + + " <name_of_the_leaf1>true</name_of_the_leaf1>\n" + + " <name_of_the_leaf3>abc</name_of_the_leaf3>\n" + + " <name_of_the_leaf2>abc</name_of_the_leaf2>\n" + + " <name_of_the_cont4>\n" + + " <name_of_the_leaf11>abc</name_of_the_leaf11>\n" + + " </name_of_the_cont4>\n" + + " <name_of_the_ll1>abc</name_of_the_ll1>\n" + + " <name_of_the_ll1>abc</name_of_the_ll1>\n" + + " </name_of_the_list1>\n" + + " <name_of_the_list1>\n" + + " <name_of_the_ll2>abc</name_of_the_ll2>\n" + + " <name_of_the_ll2>abc</name_of_the_ll2>\n" + + " <name_of_the_list5>\n" + + " <name_of_the_leaf9>abc</name_of_the_leaf9>\n" + + " </name_of_the_list5>\n" + + " <name_of_the_list5>\n" + + " <name_of_the_leaf9>abc</name_of_the_leaf9>\n" + + " </name_of_the_list5>\n" + + " <name_of_the_list4>\n" + + " <name_of_the_leaf8>abc</name_of_the_leaf8>\n" + + " </name_of_the_list4>\n" + + " <name_of_the_list4>\n" + + " <name_of_the_leaf8>abc</name_of_the_leaf8>\n" + + " </name_of_the_list4>\n" + + " <name_of_the_leaf1>true</name_of_the_leaf1>\n" + + " <name_of_the_leaf3>abc</name_of_the_leaf3>\n" + + " <name_of_the_leaf2>abc</name_of_the_leaf2>\n" + + " <name_of_the_cont4>\n" + + " <name_of_the_leaf11>abc</name_of_the_leaf11>\n" + + " </name_of_the_cont4>\n" + + " <name_of_the_ll1>abc</name_of_the_ll1>\n" + + " <name_of_the_ll1>abc</name_of_the_ll1>\n" + + " </name_of_the_list1>\n" + + " <name_of_the_cont4>\n" + + " <name_of_the_leaf10>abc</name_of_the_leaf10>" + + addSpace(ENCODE_TO_XML_YANG_COMMON_ID, 8) + "\n" + + " </name_of_the_cont4>\n" + + " <name_of_the_leaf12>abc</name_of_the_leaf12>\n" + + "</name_of_the_cont2>\n"; + + static final String ENCODE_TO_JSON_RPC_ID = "{\n" + + " \"test_name_of_the_module:input\": {\n" + + " \"name_of_the_cont14\": {\n" + + " \"name_of_the_leaf28\": \"abc\"\n" + + " },\n" + + " \"name_of_the_cont13\": {\n" + + " \"name_of_the_ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_leaf28\": \"abc\",\n" + + " \"name_of_the_list9\": [\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"name_of_the_leaf30\": \"abc\",\n" + + " \"name_of_the_ll10\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_list10\": [\n" + + " {\n" + + " \"name_of_the_leaf29\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf29\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_cont15\": {\n" + + " \"name_of_the_leaf31\": \"abc\"\n" + + " }\n" + + " }\n" + + "}"; + + static final String DECODE_FROM_JSON_RPC_ID = "{\n" + + " \"test_name_of_the_module:output\": {\n" + + " \"name_of_the_cont16\": {\n" + + " \"name_of_the_leaf32\": \"abc\"\n" + + " },\n" + + " \"name_of_the_list11\": [\n" + + " {\n" + + " \"name_of_the_leaf33\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf33\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_leaf34\": \"abc\",\n" + + " \"name_of_the_ll11\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_cont17\": {\n" + + " \"name_of_the_leaf35\": \"abc\"\n" + + " },\n" + + " \"name_of_the_cont13\": {\n" + + " \"name_of_the_cont12\": {\n" + + " \"name_of_the_leaf26\": \"abc\"\n" + + " },\n" + + " \"name_of_the_list9\": [\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " },\n" + + " {\n" + + " \"name_of_the_leaf27\": \"abc\"\n" + + " }\n" + + " ],\n" + + " \"name_of_the_ll9\": [\n" + + " \"abc\",\n" + + " \"abc\"\n" + + " ],\n" + + " \"name_of_the_leaf28\": \"abc\"\n" + + " }\n" + + " }\n" + + "}"; + + static final String ENCODE_TO_XML_RPC_ID = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<input xmlns=\"urn:opendaylight:params:xml:ns:yang:test:name\"" + + ">\n" + + " <name_of_the_cont14>\n" + + " <name_of_the_leaf28>abc</name_of_the_leaf28>\n" + + " </name_of_the_cont14>\n" + + " <name_of_the_cont13>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_leaf28>abc</name_of_the_leaf28>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + " </name_of_the_cont13>\n" + + " <name_of_the_leaf30>abc</name_of_the_leaf30>\n" + + " <name_of_the_ll10>abc</name_of_the_ll10>\n" + + " <name_of_the_ll10>abc</name_of_the_ll10>\n" + + " <name_of_the_list10>\n" + + " <name_of_the_leaf29>abc</name_of_the_leaf29>\n" + + " </name_of_the_list10>\n" + + " <name_of_the_list10>\n" + + " <name_of_the_leaf29>abc</name_of_the_leaf29>\n" + + " </name_of_the_list10>\n" + + " <name_of_the_cont15>\n" + + " <name_of_the_leaf31>abc</name_of_the_leaf31>\n" + + " </name_of_the_cont15>\n" + + "</input>\n"; + + static final String DECODE_FROM_XML_RPC_ID = "<?xml version=\"1.0\" " + + "encoding=\"UTF-8\" standalone=\"no\"?>\n" + + "<output xmlns=\"urn:opendaylight:params:xml:ns:yang:test:name" + + "\">\n" + + " <name_of_the_cont16>\n" + + " <name_of_the_leaf32>abc</name_of_the_leaf32>\n" + + " </name_of_the_cont16>\n" + + " <name_of_the_list11>\n" + + " <name_of_the_leaf33>abc</name_of_the_leaf33>\n" + + " </name_of_the_list11>\n" + + " <name_of_the_list11>\n" + + " <name_of_the_leaf33>abc</name_of_the_leaf33>\n" + + " </name_of_the_list11>\n" + + " <name_of_the_leaf34>abc</name_of_the_leaf34>\n" + + " <name_of_the_ll11>abc</name_of_the_ll11>\n" + + " <name_of_the_ll11>abc</name_of_the_ll11>\n" + + " <name_of_the_cont17>\n" + + " <name_of_the_leaf35>abc</name_of_the_leaf35>\n" + + " </name_of_the_cont17>\n" + + " <name_of_the_cont13>\n" + + " <name_of_the_cont12>\n" + + " <name_of_the_leaf26>abc</name_of_the_leaf26>\n" + + " </name_of_the_cont12>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + " <name_of_the_list9>\n" + + " <name_of_the_leaf27>abc</name_of_the_leaf27>\n" + + " </name_of_the_list9>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_ll9>abc</name_of_the_ll9>\n" + + " <name_of_the_leaf28>abc</name_of_the_leaf28>\n" + + " </name_of_the_cont13>\n" + + "</output>"; +} diff --git a/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesSerializerTest.java b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesSerializerTest.java new file mode 100644 index 000000000..c3a6b4ea8 --- /dev/null +++ b/restconf-client/provider/src/test/java/org/onap/ccsdk/sli/plugins/yangserializers/pnserializer/PropertiesSerializerTest.java @@ -0,0 +1,1144 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - CCSDK + * ================================================================================ + * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.ccsdk.sli.plugins.yangserializers.pnserializer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.opendaylight.restconf.common.context.InstanceIdentifierContext; +import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertTrue; + +public final class PropertiesSerializerTest { + private SchemaContext context; + + @Before + public void initialization() throws FileNotFoundException { + context = compileYangFile(); + } + + @Test + public void testBasicConstructs() throws SvcLogicException { + String uri = "test-yang:cont1/cont2"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont1.cont2.cont3.leaf10", "abc"); + params.put("test-yang_cont1.cont2.list1[0].leaf1", "abc"); + params.put("test-yang_cont1.cont2.list1[0].leaf2", "abc"); + params.put("test-yang_cont1.cont2.list1[0].leaf3", "abc"); + params.put("test-yang_cont1.cont2.list1[0].ll1[0]", "abc"); + params.put("test-yang_cont1.cont2.list1[0].ll1[1]", "abc"); + params.put("test-yang_cont1.cont2.list1[0].ll2[0]", "abc"); + params.put("test-yang_cont1.cont2.list1[0].ll2[1]", "abc"); + params.put("test-yang_cont1.cont2.list1[0].cont4.leaf11", "abc"); + params.put("test-yang_cont1.cont2.list1[0].list4[0].leaf8", "abc"); + params.put("test-yang_cont1.cont2.list1[0].list4[1].leaf8", "abc"); + params.put("test-yang_cont1.cont2.list1[0].list5[0].leaf9", "abc"); + params.put("test-yang_cont1.cont2.list1[0].list5[1].leaf9", "abc"); + params.put("test-yang_cont1.cont2.list1[1].leaf1", "abc"); + params.put("test-yang_cont1.cont2.list1[1].leaf2", "abc"); + params.put("test-yang_cont1.cont2.list1[1].leaf3", "abc"); + params.put("test-yang_cont1.cont2.list1[1].ll1[0]", "abc"); + params.put("test-yang_cont1.cont2.list1[1].ll1[1]", "abc"); + params.put("test-yang_cont1.cont2.list1[1].ll2[0]", "abc"); + params.put("test-yang_cont1.cont2.list1[1].ll2[1]", "abc"); + params.put("test-yang_cont1.cont2.list1[1].cont4.leaf11", "abc"); + params.put("test-yang_cont1.cont2.list1[1].list4[0].leaf8", "abc"); + params.put("test-yang_cont1.cont2.list1[1].list4[1].leaf8", "abc"); + params.put("test-yang_cont1.cont2.list1[1].list5[0].leaf9", "abc"); + params.put("test-yang_cont1.cont2.list1[1].list5[1].leaf9", "abc"); + params.put("test-yang_cont1.cont2.list2[0].leaf4", "abc"); + params.put("test-yang_cont1.cont2.list2[1].leaf4", "abc"); + params.put("test-yang_cont1.cont2.leaf5", "abc"); + params.put("test-yang_cont1.cont2.leaf6", "abc"); + params.put("test-yang_cont1.cont2.ll3[0]", "abc"); + params.put("test-yang_cont1.cont2.ll3[1]", "abc"); + params.put("test-yang_cont1.cont2.ll4[0]", "abc"); + params.put("test-yang_cont1.cont2.ll4[1]", "abc"); + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont3"), is(true)); + SingleInstanceNode cont3 = ((SingleInstanceNode) childNodes.get("cont3")); + assertThat(cont3.uri(), is("test-yang:cont1.cont2.cont3")); + assertThat(cont3.children().containsKey("leaf10"), is(true)); + + assertThat(childNodes.containsKey("list1"), is(true)); + HolderNode list1Holder = ((ListHolderNode) childNodes.get("list1")); + assertThat(list1Holder.uri(), is("test-yang:cont1.cont2.list1")); + MultiInstanceNode list10 = ((MultiInstanceNode) list1Holder.child("0")); + assertThat(list10.uri(), is("test-yang:cont1.cont2.list1[0]")); + Map<String, DataNodeChild> list10Child = list10.children(); + assertThat(list10Child.containsKey("leaf1"), is(true)); + LeafNode l = ((LeafNode) list10Child.get("leaf1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].leaf1")); + assertThat(list10Child.containsKey("leaf2"), is(true)); + l = ((LeafNode) list10Child.get("leaf2")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].leaf2")); + assertThat(list10Child.containsKey("leaf2"), is(true)); + l = ((LeafNode) list10Child.get("leaf3")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].leaf3")); + + LeafListHolderNode ll1Holder = ((LeafListHolderNode) list10Child.get("ll1")); + assertThat(ll1Holder.uri(), is("test-yang:cont1.cont2.list1[0].ll1")); + assertThat(ll1Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll1Holder.child("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].ll1[0]")); + assertThat(ll1Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll1Holder.child("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].ll1[1]")); + + LeafListHolderNode ll2Holder = ((LeafListHolderNode) list10Child.get("ll2")); + assertThat(ll2Holder.uri(), is("test-yang:cont1.cont2.list1[0].ll2")); + assertThat(ll2Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll2Holder.child("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].ll2[0]")); + assertThat(ll2Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll2Holder.child("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].ll2[1]")); + + SingleInstanceNode cont4 = ((SingleInstanceNode) list10Child.get("cont4")); + assertThat(cont4.uri(), is("test-yang:cont1.cont2.list1[0].cont4")); + assertThat(cont4.children().containsKey("leaf11"), is(true)); + l = ((LeafNode) cont4.children().get("leaf11")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].cont4.leaf11")); + + HolderNode list4Holder = ((HolderNode) list10Child.get("list4")); + assertThat(list4Holder.uri(), is("test-yang:cont1.cont2.list1[0].list4")); + Map<String, PropertiesNode> c = list4Holder.children(); + MultiInstanceNode list40 = ((MultiInstanceNode) c.get("0")); + assertThat(list40.uri(), is("test-yang:cont1.cont2.list1[0].list4[0]")); + assertThat(list40.children().containsKey("leaf8"), is(true)); + l = ((LeafNode) list40.children().get("leaf8")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].list4[0].leaf8")); + MultiInstanceNode list41 = ((MultiInstanceNode) c.get("1")); + assertThat(list41.uri(), is("test-yang:cont1.cont2.list1[0].list4[1]")); + assertThat(list41.children().containsKey("leaf8"), is(true)); + l = ((LeafNode) list41.children().get("leaf8")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].list4[1].leaf8")); + + HolderNode list5Holder = ((HolderNode) list10Child.get("list5")); + assertThat(list5Holder.uri(), is("test-yang:cont1.cont2.list1[0].list5")); + c = list5Holder.children(); + MultiInstanceNode list50 = ((MultiInstanceNode) c.get("0")); + assertThat(list50.uri(), is("test-yang:cont1.cont2.list1[0].list5[0]")); + assertThat(list50.children().containsKey("leaf9"), is(true)); + l = ((LeafNode) list50.children().get("leaf9")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].list5[0].leaf9")); + MultiInstanceNode list51 = ((MultiInstanceNode) c.get("1")); + assertThat(list51.uri(), is("test-yang:cont1.cont2.list1[0].list5[1]")); + assertThat(list51.children().containsKey("leaf9"), is(true)); + l = ((LeafNode) list51.children().get("leaf9")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[0].list5[1].leaf9")); + + MultiInstanceNode list11 = ((MultiInstanceNode) list1Holder.child("1")); + assertThat(list11.uri(), is("test-yang:cont1.cont2.list1[1]")); + Map<String, DataNodeChild> list11Child = list11.children(); + assertThat(list11Child.containsKey("leaf1"), is(true)); + l = ((LeafNode) list11Child.get("leaf1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].leaf1")); + assertThat(list11Child.containsKey("leaf2"), is(true)); + l = ((LeafNode) list11Child.get("leaf2")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].leaf2")); + assertThat(list11Child.containsKey("leaf3"), is(true)); + l = ((LeafNode) list11Child.get("leaf3")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].leaf3")); + + ll1Holder = ((LeafListHolderNode) list11Child.get("ll1")); + assertThat(ll1Holder.uri(), is("test-yang:cont1.cont2.list1[1].ll1")); + assertThat(ll1Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll1Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].ll1[0]")); + assertThat(ll1Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll1Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].ll1[1]")); + + ll2Holder = ((LeafListHolderNode) list11Child.get("ll2")); + assertThat(ll2Holder.uri(), is("test-yang:cont1.cont2.list1[1].ll2")); + assertThat(ll2Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll2Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].ll2[0]")); + assertThat(ll2Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll2Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].ll2[1]")); + + cont4 = ((SingleInstanceNode) list11Child.get("cont4")); + assertThat(cont4.uri(), is("test-yang:cont1.cont2.list1[1].cont4")); + assertThat(cont4.children().containsKey("leaf11"), is(true)); + l = ((LeafNode) cont4.children().get("leaf11")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].cont4.leaf11")); + + list4Holder = ((HolderNode) list11Child.get("list4")); + assertThat(list4Holder.uri(), is("test-yang:cont1.cont2.list1[1].list4")); + c = list4Holder.children(); + list40 = ((MultiInstanceNode) c.get("0")); + assertThat(list40.uri(), is("test-yang:cont1.cont2.list1[1].list4[0]")); + assertThat(list40.children().containsKey("leaf8"), is(true)); + l = ((LeafNode) list40.children().get("leaf8")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].list4[0].leaf8")); + list41 = ((MultiInstanceNode) c.get("1")); + assertThat(list41.uri(), is("test-yang:cont1.cont2.list1[1].list4[1]")); + assertThat(list41.children().containsKey("leaf8"), is(true)); + l = ((LeafNode) list41.children().get("leaf8")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].list4[1].leaf8")); + + list5Holder = ((HolderNode) list11Child.get("list5")); + assertThat(list5Holder.uri(), is("test-yang:cont1.cont2.list1[1].list5")); + c = list5Holder.children(); + list50 = ((MultiInstanceNode) c.get("0")); + assertThat(list50.uri(), is("test-yang:cont1.cont2.list1[1].list5[0]")); + assertThat(list50.children().containsKey("leaf9"), is(true)); + l = ((LeafNode) list50.children().get("leaf9")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].list5[0].leaf9")); + list51 = ((MultiInstanceNode) c.get("1")); + assertThat(list51.uri(), is("test-yang:cont1.cont2.list1[1].list5[1]")); + assertThat(list51.children().containsKey("leaf9"), is(true)); + l = ((LeafNode) list51.children().get("leaf9")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list1[1].list5[1].leaf9")); + + assertThat(childNodes.containsKey("list2"), is(true)); + HolderNode list2Holder = ((HolderNode) childNodes.get("list2")); + assertThat(list2Holder.uri(), is("test-yang:cont1.cont2.list2")); + InnerNode list20 = ((InnerNode) list2Holder.children().get("0")); + assertThat(list20.uri(), is("test-yang:cont1.cont2.list2[0]")); + assertThat(list20.children().containsKey("leaf4"), is(true)); + l = ((LeafNode) list20.children().get("leaf4")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list2[0].leaf4")); + InnerNode list21 = ((InnerNode) list2Holder.children().get("1")); + assertThat(list21.uri(), is("test-yang:cont1.cont2.list2[1]")); + assertThat(list21.children().containsKey("leaf4"), is(true)); + l = ((LeafNode) list21.children().get("leaf4")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list2[1].leaf4")); + + assertThat(childNodes.containsKey("leaf5"), is(true)); + l = ((LeafNode) childNodes.get("leaf5")); + assertThat(l.uri(), is("test-yang:cont1.cont2.leaf5")); + assertThat(childNodes.containsKey("leaf6"), is(true)); + l = ((LeafNode) childNodes.get("leaf6")); + assertThat(l.uri(), is("test-yang:cont1.cont2.leaf6")); + + HolderNode ll3Holder = ((HolderNode) childNodes.get("ll3")); + assertThat(ll3Holder.uri(), is("test-yang:cont1.cont2.ll3")); + assertThat(((LeafNode) ll3Holder.children().get("0")).name(), is("ll3")); + l = ((LeafNode) ll3Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll3[0]")); + assertThat(((LeafNode) ll3Holder.children().get("1")).name(), is("ll3")); + l = ((LeafNode) ll3Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll3[1]")); + + HolderNode ll4Holder = ((HolderNode) childNodes.get("ll4")); + assertThat(ll4Holder.uri(), is("test-yang:cont1.cont2.ll4")); + assertThat(((LeafNode) ll4Holder.children().get("0")).name(), is("ll4")); + l = ((LeafNode) ll4Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll4[0]")); + assertThat(((LeafNode) ll4Holder.children().get("1")).name(), is("ll4")); + l = ((LeafNode) ll4Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll4[1]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testAugment() throws SvcLogicException { + String uri = "test-yang:cont1/cont2"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont1.cont2.cont4.leaf10", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_cont5.leaf13", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_list7[0].leaf14", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_list7[1].leaf14", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_leaf15", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_ll6[0]", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_ll6[1]", "abc"); + params.put("test-yang_cont1.cont2.list6[0].leaf11", "abc"); + params.put("test-yang_cont1.cont2.list6[1].leaf11", "abc"); + params.put("test-yang_cont1.cont2.leaf12", "abc"); + params.put("test-yang_cont1.cont2.ll5[0]", "abc"); + params.put("test-yang_cont1.cont2.ll5[1]", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont4"), is(true)); + SingleInstanceNode cont4 = ((SingleInstanceNode) childNodes.get("cont4")); + for (Map.Entry<Object, Collection<PropertiesNode>> augToChild + : cont4.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + List<String> expectedNodes = new LinkedList<>(); + expectedNodes.add("test-yang:cont1.cont2.cont4.test-augment:cont5"); + expectedNodes.add("test-yang:cont1.cont2.cont4.test-augment:list7"); + expectedNodes.add("test-yang:cont1.cont2.cont4.test-augment:leaf15"); + expectedNodes.add("test-yang:cont1.cont2.cont4.test-augment:ll6"); + assertThat(expectedNodes.size(), is(child.size())); + for (PropertiesNode pNode : child) { + assertThat(expectedNodes.contains(pNode.uri()), is(true)); + if (pNode.uri().equals("test-yang:cont1.cont2.cont4.test-augment:cont5")) { + assertThat(((SingleInstanceNode) pNode).children().containsKey("leaf13"), is(true)); + LeafNode l = ((LeafNode) ((SingleInstanceNode) pNode).children().get("leaf13")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont5.leaf13")); + } else if (pNode.uri().equals("test-yang:cont1.cont2.cont4.test-augment:list7")) { + ListHolderNode list7Holder = ((ListHolderNode) pNode); + MultiInstanceNode list7 = ((MultiInstanceNode) list7Holder.child("0")); + assertThat(list7.uri(), is("test-yang:cont1.cont2.cont4.test-augment:list7[0]")); + Map<String, DataNodeChild> list7Child = list7.children(); + assertThat(list7Child.containsKey("leaf14"), is(true)); + LeafNode l = ((LeafNode) list7Child.get("leaf14")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:list7[0].leaf14")); + list7 = ((MultiInstanceNode) list7Holder.child("1")); + assertThat(list7.uri(), is("test-yang:cont1.cont2.cont4.test-augment:list7[1]")); + list7Child = list7.children(); + assertThat(list7Child.containsKey("leaf14"), is(true)); + l = ((LeafNode) list7Child.get("leaf14")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:list7[1].leaf14")); + } else if (pNode.uri().equals("test-yang:cont1.cont2.cont4.test-augment:leaf15")) { + LeafNode leaf15 = ((LeafNode) pNode); + assertThat(leaf15.name(), is("leaf15")); + assertThat(leaf15.uri(), is("test-yang:cont1.cont2.cont4.test-augment:leaf15")); + } else if (pNode.uri().equals("test-yang:cont1.cont2.cont4.test-augment:ll6")) { + LeafListHolderNode ll6Holder = ((LeafListHolderNode) pNode); + assertThat(ll6Holder.children().containsKey("0"), is(true)); + LeafNode l = ((LeafNode) ll6Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:ll6[0]")); + assertThat(ll6Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll6Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:ll6[1]")); + } + } + } + } + assertThat(cont4.uri(), is("test-yang:cont1.cont2.cont4")); + assertThat(cont4.children().containsKey("leaf10"), is(true)); + LeafNode l = ((LeafNode) cont4.children().get("leaf10")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.leaf10")); + + assertThat(childNodes.containsKey("list6"), is(true)); + HolderNode list6Holder = ((ListHolderNode) childNodes.get("list6")); + assertThat(list6Holder.uri(), is("test-yang:cont1.cont2.list6")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-yang:cont1.cont2.list6[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf11"), is(true)); + l = ((LeafNode) list6Child.get("leaf11")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list6[0].leaf11")); + list6 = ((MultiInstanceNode) list6Holder.child("1")); + assertThat(list6.uri(), is("test-yang:cont1.cont2.list6[1]")); + list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf11"), is(true)); + l = ((LeafNode) list6Child.get("leaf11")); + assertThat(l.uri(), is("test-yang:cont1.cont2.list6[1].leaf11")); + + assertThat(childNodes.containsKey("leaf12"), is(true)); + LeafNode leaf12 = ((LeafNode) childNodes.get("leaf12")); + assertThat(leaf12.name(), is("leaf12")); + assertThat(leaf12.uri(), is("test-yang:cont1.cont2.leaf12")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) childNodes.get("ll5")); + assertThat(ll5Holder.uri(), is("test-yang:cont1.cont2.ll5")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll5[0]")); + assertThat(ll5Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll5Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont1.cont2.ll5[1]")); + + Map<String, String> output = ser.decode(node); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testChoiceCase1() throws SvcLogicException { + String uri = "test-yang:cont8"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont8.cont6.leaf16", "abc"); + params.put("test-yang_cont8.list8[0].leaf18", "abc"); + params.put("test-yang_cont8.list8[1].leaf18", "abc"); + params.put("test-yang_cont8.leaf19", "abc"); + params.put("test-yang_cont8.ll7[0]", "abc"); + params.put("test-yang_cont8.ll7[1]", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont6"), is(true)); + SingleInstanceNode cont6 = ((SingleInstanceNode) childNodes.get("cont6")); + assertThat(cont6.uri(), is("test-yang:cont8.cont6")); + assertThat(cont6.children().containsKey("leaf16"), is(true)); + LeafNode l = ((LeafNode) cont6.children().get("leaf16")); + assertThat(l.uri(), is("test-yang:cont8.cont6.leaf16")); + + assertThat(childNodes.containsKey("list8"), is(true)); + HolderNode list6Holder = ((ListHolderNode) childNodes.get("list8")); + assertThat(list6Holder.uri(), is("test-yang:cont8.list8")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-yang:cont8.list8[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf18"), is(true)); + l = ((LeafNode) list6Child.get("leaf18")); + assertThat(l.uri(), is("test-yang:cont8.list8[0].leaf18")); + list6 = ((MultiInstanceNode) list6Holder.child("1")); + list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf18"), is(true)); + l = ((LeafNode) list6Child.get("leaf18")); + assertThat(l.uri(), is("test-yang:cont8.list8[1].leaf18")); + + assertThat(childNodes.containsKey("leaf19"), is(true)); + LeafNode leaf12 = ((LeafNode) childNodes.get("leaf19")); + assertThat(leaf12.name(), is("leaf19")); + assertThat(leaf12.uri(), is("test-yang:cont8.leaf19")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) childNodes.get("ll7")); + assertThat(ll5Holder.uri(), is("test-yang:cont8.ll7")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont8.ll7[0]")); + assertThat(ll5Holder.children().containsKey("1"), is(true)); + l = ((LeafNode) ll5Holder.children().get("1")); + assertThat(l.uri(), is("test-yang:cont8.ll7[1]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testChoiceCase2() throws SvcLogicException { + String uri = "test-yang:cont9"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont9.leaf20", "abc"); + params.put("test-yang_cont9.ll8[0]", "abc"); + params.put("test-yang_cont9.cont11.leaf25", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont11"), is(true)); + SingleInstanceNode cont4 = ((SingleInstanceNode) childNodes.get("cont11")); + assertThat(cont4.uri(), is("test-yang:cont9.cont11")); + assertThat(cont4.children().containsKey("leaf25"), is(true)); + LeafNode l = ((LeafNode) cont4.children().get("leaf25")); + assertThat(l.uri(), is("test-yang:cont9.cont11.leaf25")); + + assertThat(childNodes.containsKey("leaf20"), is(true)); + l = ((LeafNode) childNodes.get("leaf20")); + assertThat(l.uri(), is("test-yang:cont9.leaf20")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) childNodes.get("ll8")); + assertThat(ll5Holder.uri(), is("test-yang:cont9.ll8")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont9.ll8[0]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testChoiceCase3() throws SvcLogicException { + String uri = "test-yang:cont8/cont6"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont8.cont6.test-augment_leaf21", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + for (Map.Entry<Object, Collection<PropertiesNode>> augToChild + : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + List<String> expectedNodes = new LinkedList<>(); + expectedNodes.add("test-yang:cont8.cont6.test-augment:leaf21"); + assertThat(expectedNodes.size(), is(child.size())); + for (PropertiesNode pNode : child) { + assertThat(expectedNodes.contains(pNode.uri()), is(true)); + } + } + } + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("leaf21"), is(true)); + LeafNode leaf12 = ((LeafNode) childNodes.get("leaf21")); + assertThat(leaf12.name(), is("leaf21")); + assertThat(leaf12.uri(), is("test-yang:cont8.cont6.test-augment:leaf21")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testGrouping() throws SvcLogicException { + String uri = "test-yang:cont13"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont13.cont12.leaf26", "abc"); + params.put("test-yang_cont13.list9[0].leaf27", "abc"); + params.put("test-yang_cont13.leaf28", "abc"); + params.put("test-yang_cont13.ll9[0]", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont12"), is(true)); + SingleInstanceNode cont4 = ((SingleInstanceNode) childNodes.get("cont12")); + assertThat(cont4.uri(), is("test-yang:cont13.cont12")); + assertThat(cont4.children().containsKey("leaf26"), is(true)); + LeafNode l = ((LeafNode) cont4.children().get("leaf26")); + assertThat(l.uri(), is("test-yang:cont13.cont12.leaf26")); + + assertThat(childNodes.containsKey("list9"), is(true)); + HolderNode list6Holder = ((ListHolderNode) childNodes.get("list9")); + assertThat(list6Holder.uri(), is("test-yang:cont13.list9")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-yang:cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-yang:cont13.list9[0].leaf27")); + + assertThat(childNodes.containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) childNodes.get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-yang:cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) childNodes.get("ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testGrouping2() throws SvcLogicException { + String uri = "test-yang:cont9/cont11"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont9.cont11.leaf25", "abc"); + params.put("test-yang_cont9.cont11.cont13.cont12.leaf26", "abc"); + params.put("test-yang_cont9.cont11.cont13.list9[0].leaf27", "abc"); + params.put("test-yang_cont9.cont11.cont13.leaf28", "abc"); + params.put("test-yang_cont9.cont11.cont13.ll9[0]", "abc"); + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont13"), is(true)); + SingleInstanceNode cont13 = ((SingleInstanceNode) childNodes.get("cont13")); + assertThat(cont13.uri(), is("test-yang:cont9.cont11.cont13")); + SingleInstanceNode cont12 = ((SingleInstanceNode) cont13.children().get("cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + assertThat(cont12.uri(), is("test-yang:cont9.cont11.cont13.cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + LeafNode l = ((LeafNode) cont12.children().get("leaf26")); + assertThat(l.uri(), is("test-yang:cont9.cont11.cont13.cont12.leaf26")); + + assertThat(cont13.children().containsKey("list9"), is(true)); + HolderNode list6Holder = ((ListHolderNode) cont13.children().get("list9")); + assertThat(list6Holder.uri(), is("test-yang:cont9.cont11.cont13.list9")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-yang:cont9.cont11.cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-yang:cont9.cont11.cont13.list9[0].leaf27")); + + assertThat(cont13.children().containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) cont13.children().get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-yang:cont9.cont11.cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) cont13.children().get("ll9")); + assertThat(ll5Holder.uri(), is("test-yang:cont9.cont11.cont13.ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont9.cont11.cont13.ll9[0]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testGrouping3() throws SvcLogicException { + String uri = "test-augment:cont13"; + Map<String, String> params = new HashMap<>(); + params.put("test-augment_cont13.cont12.leaf26", "abc"); + params.put("test-augment_cont13.list9[0].leaf27", "abc"); + params.put("test-augment_cont13.leaf28", "abc"); + params.put("test-augment_cont13.ll9[0]", "abc"); + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont12"), is(true)); + SingleInstanceNode cont12 = ((SingleInstanceNode) childNodes.get("cont12")); + assertThat(cont12.uri(), is("test-augment:cont13.cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + LeafNode l = ((LeafNode) cont12.children().get("leaf26")); + assertThat(l.uri(), is("test-augment:cont13.cont12.leaf26")); + + assertThat(childNodes.containsKey("list9"), is(true)); + HolderNode list6Holder = ((ListHolderNode) childNodes.get("list9")); + assertThat(list6Holder.uri(), is("test-augment:cont13.list9")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-augment:cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-augment:cont13.list9[0].leaf27")); + + assertThat(childNodes.containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) childNodes.get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-augment:cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) childNodes.get("ll9")); + assertThat(ll5Holder.uri(), is("test-augment:cont13.ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-augment:cont13.ll9[0]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testGrouping4() throws SvcLogicException { + String uri = "test-yang:cont1/cont2/cont4"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont1.cont2.cont4.test-augment_cont13.cont12.leaf26", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_cont13.list9[0].leaf27", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_cont13.leaf28", "abc"); + params.put("test-yang_cont1.cont2.cont4.test-augment_cont13.ll9[0]", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + for (Map.Entry<Object, Collection<PropertiesNode>> augToChild + : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + List<String> expectedNodes = new LinkedList<>(); + expectedNodes.add("test-yang:cont1.cont2.cont4.test-augment:cont13"); + assertThat(expectedNodes.size(), is(child.size())); + for (PropertiesNode pNode : child) { + assertThat(expectedNodes.contains(pNode.uri()), is(true)); + SingleInstanceNode cont13 = ((SingleInstanceNode) pNode); + assertThat(cont13.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13")); + SingleInstanceNode cont12 = ((SingleInstanceNode) cont13.children().get("cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + LeafNode l = ((LeafNode) cont12.children().get("leaf26")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.cont12.leaf26")); + + assertThat(cont13.children().containsKey("list9"), is(true)); + HolderNode list6Holder = ((ListHolderNode) cont13.children().get("list9")); + assertThat(list6Holder.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.list9")); + MultiInstanceNode list6 = ((MultiInstanceNode) list6Holder.child("0")); + assertThat(list6.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list6.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.list9[0].leaf27")); + + assertThat(cont13.children().containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) cont13.children().get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) cont13.children().get("ll9")); + assertThat(ll5Holder.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:cont1.cont2.cont4.test-augment:cont13.ll9[0]")); + } + } + } + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testRpcInput() throws SvcLogicException { + String uri = "test-yang:create-sfc"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_create-sfc.input.cont14.leaf28", "abc"); + params.put("test-yang_create-sfc.input.list10[0].leaf29", "abc"); + params.put("test-yang_create-sfc.input.leaf30", "abc"); + params.put("test-yang_create-sfc.input.ll10[0]", "abc"); + params.put("test-yang_create-sfc.input.cont15.leaf31", "abc"); + params.put("test-yang_create-sfc.input.cont13.cont12.leaf26", "abc"); + params.put("test-yang_create-sfc.input.cont13.list9[0].leaf27", "abc"); + params.put("test-yang_create-sfc.input.cont13.leaf28", "abc"); + params.put("test-yang_create-sfc.input.cont13.ll9[0]", "abc"); + params.put("test-yang_create-sfc.input.test-augment_leaf36", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + PropertiesNode input = childNodes.get("input"); + assertThat(input.uri(), is("test-yang:create-sfc.input")); + for (Map.Entry<Object, Collection<PropertiesNode>> augToChild + : node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> child = augToChild.getValue(); + if (!child.isEmpty()) { + List<String> expectedNodes = new LinkedList<>(); + expectedNodes.add("test-yang:create-sfc.input.test-augment:leaf36"); + assertThat(expectedNodes.size(), is(child.size())); + for (PropertiesNode pNode : child) { + assertThat(expectedNodes.contains(pNode.uri()), is(true)); + LeafNode leaf37 = ((LeafNode) pNode); + assertThat(leaf37.name(), is("leaf36")); + assertThat(leaf37.uri(), is("test-yang:create-sfc.input.test-augment:leaf36")); + } + } + } + childNodes = ((InnerNode) input).children(); + + assertThat(childNodes.containsKey("cont14"), is(true)); + SingleInstanceNode cont14 = ((SingleInstanceNode) childNodes.get("cont14")); + assertThat(cont14.uri(), is("test-yang:create-sfc.input.cont14")); + assertThat(cont14.children().containsKey("leaf28"), is(true)); + LeafNode l = ((LeafNode) cont14.children().get("leaf28")); + assertThat(l.uri(), is("test-yang:create-sfc.input.cont14.leaf28")); + + assertThat(childNodes.containsKey("list10"), is(true)); + HolderNode list10Holder = ((ListHolderNode) childNodes.get("list10")); + assertThat(list10Holder.uri(), is("test-yang:create-sfc.input.list10")); + MultiInstanceNode list10 = ((MultiInstanceNode) list10Holder.child("0")); + assertThat(list10.uri(), is("test-yang:create-sfc.input.list10[0]")); + Map<String, DataNodeChild> list10Child = list10.children(); + assertThat(list10Child.containsKey("leaf29"), is(true)); + l = ((LeafNode) list10Child.get("leaf29")); + assertThat(l.uri(), is("test-yang:create-sfc.input.list10[0].leaf29")); + + assertThat(childNodes.containsKey("leaf30"), is(true)); + LeafNode leaf30 = ((LeafNode) childNodes.get("leaf30")); + assertThat(leaf30.name(), is("leaf30")); + assertThat(leaf30.uri(), is("test-yang:create-sfc.input.leaf30")); + + LeafListHolderNode ll10Holder = ((LeafListHolderNode) childNodes.get("ll10")); + assertThat(ll10Holder.uri(), is("test-yang:create-sfc.input.ll10")); + assertThat(ll10Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll10Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:create-sfc.input.ll10[0]")); + + assertThat(childNodes.containsKey("cont15"), is(true)); + SingleInstanceNode cont15 = ((SingleInstanceNode) childNodes.get("cont15")); + assertThat(cont15.uri(), is("test-yang:create-sfc.input.cont15")); + assertThat(cont15.children().containsKey("leaf31"), is(true)); + l = ((LeafNode) cont15.children().get("leaf31")); + assertThat(l.uri(), is("test-yang:create-sfc.input.cont15.leaf31")); + + assertThat(childNodes.containsKey("cont13"), is(true)); + SingleInstanceNode cont13 = ((SingleInstanceNode) childNodes.get("cont13")); + assertThat(cont13.uri(), is("test-yang:create-sfc.input.cont13")); + SingleInstanceNode cont12 = ((SingleInstanceNode) cont13.children().get("cont12")); + assertThat(cont12.uri(), is("test-yang:create-sfc.input.cont13.cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + l = ((LeafNode) cont12.children().get("leaf26")); + assertThat(l.uri(), is("test-yang:create-sfc.input.cont13.cont12.leaf26")); + + assertThat(cont13.children().containsKey("list9"), is(true)); + HolderNode list9Holder = ((ListHolderNode) cont13.children().get("list9")); + assertThat(list9Holder.uri(), is("test-yang:create-sfc.input.cont13.list9")); + MultiInstanceNode list9 = ((MultiInstanceNode) list9Holder.child("0")); + assertThat(list9.uri(), is("test-yang:create-sfc.input.cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list9.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-yang:create-sfc.input.cont13.list9[0].leaf27")); + + assertThat(cont13.children().containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) cont13.children().get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-yang:create-sfc.input.cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) cont13.children().get("ll9")); + assertThat(ll5Holder.uri(), is("test-yang:create-sfc.input.cont13.ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:create-sfc.input.cont13.ll9[0]")); + + Map<String, String> output = ser.decode(node); + assertThat(output.size(), is(params.size())); + for (Map.Entry<String, String> entry : output.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testRpcOutput() throws SvcLogicException { + String uri = "test-yang:create-sfc"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_create-sfc.output.cont16.leaf32", "abc"); + params.put("test-yang_create-sfc.output.list11[0].leaf33", "abc"); + params.put("test-yang_create-sfc.output.leaf34", "abc"); + params.put("test-yang_create-sfc.output.ll11[0]", "abc"); + params.put("test-yang_create-sfc.output.cont17.leaf35", "abc"); + params.put("test-yang_create-sfc.output.cont13.cont12.leaf26", "abc"); + params.put("test-yang_create-sfc.output.cont13.list9[0].leaf27", "abc"); + params.put("test-yang_create-sfc.output.cont13.leaf28", "abc"); + params.put("test-yang_create-sfc.output.cont13.ll9[0]", "abc"); + params.put("test-yang_create-sfc.output.test-augment_leaf37", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + PropertiesNode output = childNodes.get("output"); + assertThat(output.uri(), is("test-yang:create-sfc.output")); + for (Map.Entry<Object, Collection<PropertiesNode>> augmentationToChild : + node.augmentations().asMap().entrySet()) { + Collection<PropertiesNode> c = augmentationToChild.getValue(); + if(!c.isEmpty()) { + List<String> expectedNodes = new LinkedList<>(); + expectedNodes.add("test-yang:create-sfc.output.test-augment:leaf37"); + assertThat(expectedNodes.size(), is(expectedNodes)); + for (PropertiesNode pNode : c) { + assertThat(expectedNodes.contains(pNode.uri()), is(true)); + LeafNode leaf37 = ((LeafNode) pNode); + assertThat(leaf37.name(), is("leaf37")); + assertThat(leaf37.uri(), is("test-yang:create-sfc.output.test-augment:leaf37")); + } + } + } + childNodes = ((InnerNode) output).children(); + + assertThat(childNodes.containsKey("cont16"), is(true)); + SingleInstanceNode cont16 = ((SingleInstanceNode) childNodes.get("cont16")); + assertThat(cont16.uri(), is("test-yang:create-sfc.output.cont16")); + assertThat(cont16.children().containsKey("leaf32"), is(true)); + LeafNode l = ((LeafNode) cont16.children().get("leaf32")); + assertThat(l.uri(), is("test-yang:create-sfc.output.cont16.leaf32")); + + assertThat(childNodes.containsKey("list11"), is(true)); + HolderNode list11Holder = ((ListHolderNode) childNodes.get("list11")); + assertThat(list11Holder.uri(), is("test-yang:create-sfc.output.list11")); + MultiInstanceNode list11 = ((MultiInstanceNode) list11Holder.child("0")); + assertThat(list11.uri(), is("test-yang:create-sfc.output.list11[0]")); + Map<String, DataNodeChild> list11Child = list11.children(); + assertThat(list11Child.containsKey("leaf33"), is(true)); + l = ((LeafNode) list11Child.get("leaf33")); + assertThat(l.uri(), is("test-yang:create-sfc.output.list11[0].leaf33")); + + assertThat(childNodes.containsKey("leaf34"), is(true)); + LeafNode leaf34 = ((LeafNode) childNodes.get("leaf34")); + assertThat(leaf34.name(), is("leaf34")); + assertThat(leaf34.uri(), is("test-yang:create-sfc.output.leaf34")); + + LeafListHolderNode ll10Holder = ((LeafListHolderNode) childNodes.get("ll11")); + assertThat(ll10Holder.uri(), is("test-yang:create-sfc.output.ll11")); + assertThat(ll10Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll10Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:create-sfc.output.ll11[0]")); + + assertThat(childNodes.containsKey("cont17"), is(true)); + SingleInstanceNode cont17 = ((SingleInstanceNode) childNodes.get("cont17")); + assertThat(cont17.uri(), is("test-yang:create-sfc.output.cont17")); + assertThat(cont17.children().containsKey("leaf35"), is(true)); + l = ((LeafNode) cont17.children().get("leaf35")); + assertThat(l.uri(), is("test-yang:create-sfc.output.cont17.leaf35")); + + assertThat(childNodes.containsKey("cont13"), is(true)); + SingleInstanceNode cont13 = ((SingleInstanceNode) childNodes.get("cont13")); + assertThat(cont13.uri(), is("test-yang:create-sfc.output.cont13")); + SingleInstanceNode cont12 = ((SingleInstanceNode) cont13.children().get("cont12")); + assertThat(cont12.uri(), is("test-yang:create-sfc.output.cont13.cont12")); + assertThat(cont12.children().containsKey("leaf26"), is(true)); + l = ((LeafNode) cont12.children().get("leaf26")); + assertThat(l.uri(), is("test-yang:create-sfc.output.cont13.cont12.leaf26")); + + assertThat(cont13.children().containsKey("list9"), is(true)); + HolderNode list9Holder = ((ListHolderNode) cont13.children().get("list9")); + assertThat(list9Holder.uri(), is("test-yang:create-sfc.output.cont13.list9")); + MultiInstanceNode list9 = ((MultiInstanceNode) list9Holder.child("0")); + assertThat(list9.uri(), is("test-yang:create-sfc.output.cont13.list9[0]")); + Map<String, DataNodeChild> list6Child = list9.children(); + assertThat(list6Child.containsKey("leaf27"), is(true)); + l = ((LeafNode) list6Child.get("leaf27")); + assertThat(l.uri(), is("test-yang:create-sfc.output.cont13.list9[0].leaf27")); + + assertThat(cont13.children().containsKey("leaf28"), is(true)); + LeafNode leaf12 = ((LeafNode) cont13.children().get("leaf28")); + assertThat(leaf12.name(), is("leaf28")); + assertThat(leaf12.uri(), is("test-yang:create-sfc.output.cont13.leaf28")); + + LeafListHolderNode ll5Holder = ((LeafListHolderNode) cont13.children().get("ll9")); + assertThat(ll5Holder.uri(), is("test-yang:create-sfc.output.cont13.ll9")); + assertThat(ll5Holder.children().containsKey("0"), is(true)); + l = ((LeafNode) ll5Holder.children().get("0")); + assertThat(l.uri(), is("test-yang:create-sfc.output.cont13.ll9[0]")); + + Map<String, String> output1 = ser.decode(node); + assertThat(output1.size(), is(params.size())); + for (Map.Entry<String, String> entry : output1.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testContainerSameName() throws SvcLogicException { + String uri = "test-yang:cont18"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont18.cont18.list12[0].list12[0].leaf36", "abc"); + params.put("test-yang_cont18.cont18.list12[0].leaf36", "hi"); + params.put("test-yang_cont18.cont18.list12[1].list12[0].leaf36", "xyz"); + params.put("test-yang_cont18.cont18.list12[1].list12[1].leaf36", "hey!"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + + assertThat(childNodes.containsKey("cont18"), is(true)); + node = childNodes.get("cont18"); + assertThat(node.uri(), is("test-yang:cont18.cont18")); + childNodes = ((InnerNode) node).children(); + + assertThat(childNodes.containsKey("list12"), is(true)); + HolderNode holder = ((ListHolderNode) childNodes.get("list12")); + assertThat(holder.uri(), is("test-yang:cont18.cont18.list12")); + MultiInstanceNode node1 = ((MultiInstanceNode) holder.child("0")); + assertThat(node1.uri(), is("test-yang:cont18.cont18.list12[0]")); + Map<String, DataNodeChild> list12Child = node1.children(); + + assertThat(list12Child.containsKey("leaf36"), is(true)); + LeafNode leaf = ((LeafNode) list12Child.get("leaf36")); + assertThat(leaf.value(), is("hi")); + assertThat(leaf.uri(), is("test-yang:cont18.cont18.list12[0].leaf36")); + + assertThat(list12Child.containsKey("list12"), is(true)); + HolderNode holder1 = ((ListHolderNode) list12Child.get("list12")); + assertThat(holder1.uri(), is("test-yang:cont18.cont18.list12[0].list12")); + node1 = ((MultiInstanceNode) holder1.child("0")); + assertThat(node1.uri(), is("test-yang:cont18.cont18.list12[0].list12[0]")); + list12Child = node1.children(); + assertThat(list12Child.containsKey("leaf36"), is(true)); + leaf = ((LeafNode) list12Child.get("leaf36")); + assertThat(leaf.value(), is("abc")); + assertThat(leaf.uri(), is("test-yang:cont18.cont18.list12[0].list12[0].leaf36")); + + node1 = ((MultiInstanceNode) holder.child("1")); + assertThat(node1.uri(), is("test-yang:cont18.cont18.list12[1]")); + list12Child = node1.children(); + assertThat(list12Child.containsKey("list12"), is(true)); + holder = ((ListHolderNode) list12Child.get("list12")); + assertThat(holder.uri(), is("test-yang:cont18.cont18.list12[1].list12")); + node1 = ((MultiInstanceNode) holder.child("0")); + assertThat(node1.uri(), is("test-yang:cont18.cont18.list12[1].list12[0]")); + assertThat(node1.children().containsKey("leaf36"), is(true)); + leaf = ((LeafNode) node1.children().get("leaf36")); + assertThat(leaf.value(), is("xyz")); + assertThat(leaf.uri(), is("test-yang:cont18.cont18.list12[1].list12[0].leaf36")); + + node1 = ((MultiInstanceNode) holder.child("1")); + assertThat(node1.uri(), is("test-yang:cont18.cont18.list12[1].list12[1]")); + assertThat(node1.children().containsKey("leaf36"), is(true)); + leaf = ((LeafNode) node1.children().get("leaf36")); + assertThat(leaf.value(), is("hey!")); + assertThat(leaf.uri(), is("test-yang:cont18.cont18.list12[1].list12[1].leaf36")); + + Map<String, String> output1 = ser.decode(node); + assertThat(output1.size(), is(params.size())); + for (Map.Entry<String, String> entry : output1.entrySet()) { + assertTrue(params.containsKey(entry.getKey())); + } + } + + @Test + public void testPropertiesWithoutSchema() throws SvcLogicException { + String uri = "test-yang:cont18"; + Map<String, String> params = new HashMap<>(); + params.put("test-yang_cont18.leaf40", "abc"); + params.put("leaf41", "hi"); + params.put("test-yang_cont18.leaf41", "abc"); + + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + assertThat(childNodes.containsKey("leaf40"), is(true)); + node = childNodes.get("leaf40"); + assertThat(node.uri(), is("test-yang:cont18.leaf40")); + } + + @Test + public void testIdentityRef() throws SvcLogicException { + String uri = "identity-test:test"; + Map<String, String> params = new HashMap<>(); + params.put("identity-test_test.con1.interface", "identity-types" + + ":physical"); + params.put("identity-test_test.con1.interfaces.int-list[0].iden", "identity-test:Giga"); + params.put("identity-test_test.con1.interfaces.int-list[0].available.ll[0]", "identity-types:Loopback"); + params.put("identity-test_test.con1.interfaces.int-list[0].available.leaf1", "identity-types-second:Ethernet"); + params.put("identity-test_test.con1.interfaces.int-list[0].available.leaf2", "identity-types-second:iden2"); + InstanceIdentifierContext<?> iCtx = ParserIdentifier + .toInstanceIdentifier(uri, context, null); + + PropertiesNodeSerializer ser = new MdsalPropertiesNodeSerializer( + iCtx.getSchemaNode(), context, uri); + PropertiesNode node = ser.encode(params); + Map<String, PropertiesNode> childNodes = ((RootNode) node).children(); + assertThat(childNodes.containsKey("con1"), is(true)); + node = childNodes.get("con1"); + assertThat(node.uri(), is("identity-test:test.con1")); + LeafNode l = ((LeafNode) ((SingleInstanceNode) node).children().get("interface")); + assertThat(l.uri(), is("identity-test:test.con1.interface")); + assertThat(l.valueNs().moduleName(), is("identity-types")); + assertThat(l.valueNs().moduleNs().toString(), is("identity:list:ns:test:json:ser")); + + // identity type inside union + node = ((SingleInstanceNode) ((SingleInstanceNode) node).children().get("interfaces")); + node = ((ListHolderNode) ((SingleInstanceNode) node).children().get("int-list")); + node = ((MultiInstanceNode) ((ListHolderNode) node).children().get("0")); + l = ((LeafNode) ((MultiInstanceNode) node).children().get("iden")); + assertThat(l.uri(), is("identity-test:test.con1.interfaces.int-list[0].iden")); + assertThat(l.valueNs().moduleName(), is("identity-test")); + assertThat(l.valueNs().moduleNs().toString(), is("identity:ns:test:json:ser")); + + // leaf-list test + node = (SingleInstanceNode) ((MultiInstanceNode) node).children().get("available"); + LeafListHolderNode holder = (LeafListHolderNode) ((SingleInstanceNode) node).children().get("ll"); + l = ((LeafNode) holder.children().get("0")); + assertThat(l.uri(), is("identity-test:test.con1.interfaces.int-list[0].available.ll[0]")); + assertThat(l.valueNs().moduleName(), is("identity-types")); + assertThat(l.valueNs().moduleNs().toString(), is("identity:list:ns:test:json:ser")); + + // leaf-ref test + l = ((LeafNode) ((SingleInstanceNode) node).children().get("leaf1")); + assertThat(l.uri(), is("identity-test:test.con1.interfaces.int-list[0].available.leaf1")); + assertThat(l.valueNs().moduleName(), is("identity-types-second")); + assertThat(l.valueNs().moduleNs().toString(), is("identity:list:second:ns:test:json:ser")); + + // list of base identity test + l = ((LeafNode) ((SingleInstanceNode) node).children().get("leaf2")); + assertThat(l.uri(), is("identity-test:test.con1.interfaces.int-list[0].available.leaf2")); + assertThat(l.valueNs().moduleName(), is("identity-types-second")); + assertThat(l.valueNs().moduleNs().toString(), is("identity:list:second:ns:test:json:ser")); + } + + public static SchemaContext compileYangFile() throws FileNotFoundException { + String path = PropertiesSerializerTest.class.getResource("/yang").getPath(); + File dir = new File(path); + String[] fileList = dir.list(); + List<File> yangFiles = new ArrayList<File>(); + if (fileList == null) { + throw new FileNotFoundException("/yang"); + } + for (int i = 0; i < fileList.length; i++) { + final String fileName = fileList[i]; + if (new File(dir, fileName).isDirectory() == false) { + yangFiles.add(new File(dir, fileName)); + } + } + return YangParserTestUtils.parseYangFiles(yangFiles); + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/test/resources/yang/execution-service.yang b/restconf-client/provider/src/test/resources/yang/execution-service.yang new file mode 100644 index 000000000..d7cf68f12 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/execution-service.yang @@ -0,0 +1,43 @@ +module execution-service { + yang-version 1.1; + namespace "cds:workflow:rest"; + prefix "cds"; + + revision "2019-05-21"; + + container process { + container commonHeader { + leaf originatorId { + type string; + } + leaf requestId { + type string; + } + leaf subRequestId { + type string; + } + } + container actionIdentifiers { + leaf blueprintName { + type string; + } + leaf blueprintVersion { + type string; + } + leaf actionName { + type string; + } + leaf mode { + type string; + } + } + container payload { + leaf-list template-prefix { + type string; + } + container resource-assignment-request { + anyxml resource-assignment-properties; + } + } + } +} diff --git a/restconf-client/provider/src/test/resources/yang/identity-test.yang b/restconf-client/provider/src/test/resources/yang/identity-test.yang new file mode 100644 index 000000000..12ef717f6 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/identity-test.yang @@ -0,0 +1,77 @@ +module identity-test { + yang-version 1.1; + namespace "identity:ns:test:json:ser"; + prefix "id"; + + import identity-types { + prefix "type"; + } + + import identity-types-second { + prefix "sec"; + } + + revision "2013-07-15"; + + identity optical { + base type:int-type; + } + + identity Giga { + base type:physical; + } + + typedef available { + type identityref { + base "type:physical"; + } + } + + typedef typed{ + type union { + type int32; + type int8; + type identityref { + base type:int-type; + } + } + } + + container test { + leaf l { + type string; + } + container con1 { + leaf interface { + type identityref { + base "type:int-type"; + } + } + container interfaces { + list int-list { + key "iden"; + leaf iden { + type "id:typed"; + } + container available { + leaf-list ll { + type available; + } + leaf leaf1 { + type leafref { + path "../../iden"; + } + } + + leaf leaf2 { + type identityref { + base type:int-type; + base sec:iden1; + } + } + } + } + } + } + } +} diff --git a/restconf-client/provider/src/test/resources/yang/identity-types-second.yang b/restconf-client/provider/src/test/resources/yang/identity-types-second.yang new file mode 100644 index 000000000..98d6a6e60 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/identity-types-second.yang @@ -0,0 +1,25 @@ +module identity-types-second { + yang-version 1; + namespace "identity:list:second:ns:test:json:ser"; + prefix "sec"; + + import identity-types { + prefix "type"; + } + + revision "2013-07-15"; + + identity virtual { + base type:int-type; + } + + identity Ethernet { + base type:physical; + } + + identity iden1; + + identity iden2 { + base iden1; + } +} diff --git a/restconf-client/provider/src/test/resources/yang/identity-types.yang b/restconf-client/provider/src/test/resources/yang/identity-types.yang new file mode 100644 index 000000000..25c8fa54f --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/identity-types.yang @@ -0,0 +1,17 @@ +module identity-types { + yang-version 1; + namespace "identity:list:ns:test:json:ser"; + prefix "type"; + revision "2013-07-15"; + + identity int-type { + } + + identity physical { + base int-type; + } + + identity Loopback { + base physical; + } +} diff --git a/restconf-client/provider/src/test/resources/yang/test-augment.yang b/restconf-client/provider/src/test/resources/yang/test-augment.yang new file mode 100644 index 000000000..795000d39 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/test-augment.yang @@ -0,0 +1,106 @@ +module test-augment { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:augment"; + prefix "hello"; + + import test-yang { + prefix t; + } + + revision "2015-01-05" { + description "Initial revision of hello model"; + } + + augment "/t:cont1/t:cont2/t:cont4" { + container cont5 { + leaf leaf13 { + type empty; + } + } + list list7 { + leaf leaf14 { + type instance-identifier; + } + } + leaf leaf15 { + type string; + } + leaf-list ll6 { + type union { + type int32; + type enumeration { + enum "unbounded"; + } + } + } + uses "t:g1"; + } + + uses "t:g1"; + augment "/t:ch1/t:c1/t:cont8/t:cont6" { + choice ch2 { + case c3 { + leaf leaf21 { + type string; + } + } + case c4 { + leaf leaf22 { + type enumeration { + enum zero; + enum one; + enum seven { + value 7; + } + } + } + } + } + } + + augment "/t:ch1" { + case c5 { + container cont10 { + leaf leaf23 { + type string; + } + } + } + } + + augment "/t:ch1/t:c1" { + container cont7 { + leaf leaf24 { + type string; + } + } + } + + augment "/t:cont13/t:cont12" { + leaf leaf29 { + type string; + } + } + + augment "/t:create-sfc/t:input" { + leaf leaf36 { + type bits { + bit angle { + position 0; + } + bit degree { + position 1; + } + bit movement { + position 2; + } + } + } + } + + augment "/t:create-sfc/t:output" { + leaf leaf37 { + type boolean; + } + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/test/resources/yang/test-yang.yang b/restconf-client/provider/src/test/resources/yang/test-yang.yang new file mode 100644 index 000000000..b2bf06003 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/test-yang.yang @@ -0,0 +1,231 @@ +module test-yang { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:test"; + prefix "hello"; + + revision "2015-01-05" { + description "Initial revision of hello model"; + } + + container cont1 { + container cont2 { + container cont3 { + leaf leaf10 { + type string; + } + } + list list1 { + key "leaf1 leaf2"; + leaf leaf1 { + type empty; + } + leaf leaf2 { + type string; + } + leaf leaf3 { + type string; + } + leaf-list ll1 { + type string; + } + leaf-list ll2 { + type string; + } + container cont4 { + leaf leaf11 { + type string; + } + } + list list4 { + leaf leaf8 { + type string; + } + } + list list5 { + leaf leaf9 { + type string; + } + } + } + list list2 { + leaf leaf4 { + type string; + } + } + leaf leaf5 { + type string; + } + leaf leaf6 { + type string; + } + leaf-list ll3 { + type string; + } + leaf-list ll4 { + type string; + } + } + } + + augment "/cont1/cont2" { + container cont4 { + leaf leaf10 { + type string; + } + } + list list6 { + leaf leaf11 { + type string; + } + } + leaf leaf12 { + type string; + } + leaf-list ll5 { + type string; + } + } + + choice ch1 { + case c1 { + container cont8 { + container cont6 { + leaf leaf16 { + type string; + } + } + list list8 { + leaf leaf18 { + type string; + } + } + leaf leaf19 { + type string; + } + leaf-list ll7 { + type string; + } + } + } + case c2 { + container cont9 { + leaf leaf20 { + type string; + } + leaf-list ll8 { + type string; + } + container cont11 { + choice ch3 { + case c1 { + leaf leaf25 { + type string; + } + uses g1; + } + } + } + } + } + } + + grouping g1 { + container cont13 { + container cont12 { + leaf leaf26 { + type string; + } + } + list list9 { + leaf leaf27 { + type string; + } + } + leaf leaf28 { + type string; + } + leaf-list ll9 { + type string; + } + } + } + + uses g1; + + rpc create-sfc { + input { + container cont14 { + leaf leaf28 { + type string; + } + } + list list10 { + leaf leaf29 { + type string; + } + } + leaf leaf30 { + type string; + } + leaf-list ll10 { + type string; + } + choice ch3 { + case c1 { + container cont15 { + leaf leaf31 { + type string; + } + } + } + } + uses g1; + } + output { + container cont16 { + leaf leaf32 { + type string; + } + } + list list11 { + leaf leaf33 { + type string; + } + } + leaf leaf34 { + type string; + } + leaf-list ll11 { + type string; + } + choice ch4 { + case c1 { + container cont17 { + leaf leaf35 { + type string; + } + } + } + } + uses g1; + } + } + + container cont18 { + container cont18 { + list list12 { + list list12 { + leaf leaf36 { + type string; + } + } + leaf leaf36 { + type string; + } + } + } + leaf leaf40 { + type string; + } + } +}
\ No newline at end of file diff --git a/restconf-client/provider/src/test/resources/yang/test_augment_1_for_module.yang b/restconf-client/provider/src/test/resources/yang/test_augment_1_for_module.yang new file mode 100644 index 000000000..d2eeea7d1 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/test_augment_1_for_module.yang @@ -0,0 +1,108 @@ +module test_augment_1_for_module { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:test:augment:name"; + prefix "augment-name"; + + import test_name_of_the_module { + prefix aug; + } + + revision "2015-01-05" { + description "Initial revision of hello model"; + } + + augment "/aug:name_of_the_cont1/aug:name_of_the_cont2/aug:name_of_the_cont4" { + container name_of_the_cont5 { + leaf name_of_the_leaf13 { + type empty; + } + } + list name_of_the_list7 { + leaf name_of_the_leaf14 { + type instance-identifier; + } + } + leaf name_of_the_leaf15 { + type string; + } + leaf-list name_of_the_ll6 { + type union { + type int32; + type enumeration { + enum "unbounded"; + } + } + } + uses "aug:name_of_the_g1"; + } + + uses "aug:name_of_the_g1"; + + augment "/aug:name_of_the_cont1/aug:name_of_the_cont2/aug:name_of_the_cont3" { + choice name_of_the_ch2 { + case name_of_the_c3 { + leaf name_of_the_leaf21 { + type string; + } + } + case name_of_the_c4 { + leaf name_of_the_leaf22 { + type enumeration { + enum zero; + enum one; + enum seven { + value 7; + } + } + } + } + } + } + + augment "/aug:name_of_the_ch1" { + case name_of_the_c5 { + container name_of_the_cont10 { + leaf name_of_the_leaf23 { + type string; + } + } + } + } + + augment "/aug:name_of_the_ch1/aug:name_of_the_c1" { + container name_of_the_cont7 { + leaf name_of_the_leaf24 { + type string; + } + } + } + + augment "/aug:name_of_the_cont13/aug:name_of_the_cont12" { + leaf name_of_the_leaf29 { + type string; + } + } + + augment "/aug:name_of_the_create-sfc/aug:input" { + leaf name_of_the_leaf36 { + type bits { + bit angle { + position 0; + } + bit degree { + position 1; + } + bit movement { + position 2; + } + } + } + } + + augment "/aug:name_of_the_create-sfc/aug:output" { + leaf leaf37 { + type boolean; + } + } + +}
\ No newline at end of file diff --git a/restconf-client/provider/src/test/resources/yang/test_name_of_the_module.yang b/restconf-client/provider/src/test/resources/yang/test_name_of_the_module.yang new file mode 100644 index 000000000..973475ee7 --- /dev/null +++ b/restconf-client/provider/src/test/resources/yang/test_name_of_the_module.yang @@ -0,0 +1,231 @@ +module test_name_of_the_module { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:test:name"; + prefix "name"; + + revision "2015-01-05" { + description "Initial revision of hello model"; + } + + container name_of_the_cont1 { + container name_of_the_cont2 { + container name_of_the_cont3 { + leaf name_of_the_leaf10 { + type string; + } + } + list name_of_the_list1 { + key "name_of_the_leaf1 name_of_the_leaf2"; + leaf name_of_the_leaf1 { + type empty; + } + leaf name_of_the_leaf2 { + type string; + } + leaf name_of_the_leaf3 { + type string; + } + leaf-list name_of_the_ll1 { + type string; + } + leaf-list name_of_the_ll2 { + type string; + } + container name_of_the_cont4 { + leaf name_of_the_leaf11 { + type string; + } + } + list name_of_the_list4 { + leaf name_of_the_leaf8 { + type string; + } + } + list name_of_the_list5 { + leaf name_of_the_leaf9 { + type string; + } + } + } + list name_of_the_list2 { + leaf name_of_the_leaf4 { + type string; + } + } + leaf name_of_the_leaf5 { + type string; + } + leaf name_of_the_leaf6 { + type string; + } + leaf-list name_of_the_ll3 { + type string; + } + leaf-list name_of_the_ll4 { + type string; + } + } + } + + augment "/name_of_the_cont1/name_of_the_cont2" { + container name_of_the_cont4 { + leaf name_of_the_leaf10 { + type string; + } + } + list name_of_the_list6 { + leaf name_of_the_leaf11 { + type string; + } + } + leaf name_of_the_leaf12 { + type string; + } + leaf-list name_of_the_ll5 { + type string; + } + } + + choice name_of_the_ch1 { + case name_of_the_c1 { + container name_of_the_cont8 { + container name_of_the_cont6 { + leaf name_of_the_leaf16 { + type string; + } + } + list name_of_the_list8 { + leaf name_of_the_leaf18 { + type string; + } + } + leaf name_of_the_leaf19 { + type string; + } + leaf-list name_of_the_ll7 { + type string; + } + } + } + case name_of_the_c2 { + container name_of_the_cont9 { + leaf name_of_the_leaf20 { + type string; + } + leaf-list name_of_the_ll8 { + type string; + } + container name_of_the_cont11 { + choice name_of_the_ch3 { + case name_of_the_c1 { + leaf name_of_the_leaf25 { + type string; + } + uses name_of_the_g1; + } + } + } + } + } + } + + grouping name_of_the_g1 { + container name_of_the_cont13 { + container name_of_the_cont12 { + leaf name_of_the_leaf26 { + type string; + } + } + list name_of_the_list9 { + leaf name_of_the_leaf27 { + type string; + } + } + leaf name_of_the_leaf28 { + type string; + } + leaf-list name_of_the_ll9 { + type string; + } + } + } + + uses name_of_the_g1; + + rpc name_of_the_create-sfc { + input { + container name_of_the_cont14 { + leaf name_of_the_leaf28 { + type string; + } + } + list name_of_the_list10 { + leaf name_of_the_leaf29 { + type string; + } + } + leaf name_of_the_leaf30 { + type string; + } + leaf-list name_of_the_ll10 { + type string; + } + choice name_of_the_ch3 { + case name_of_the_c1 { + container name_of_the_cont15 { + leaf name_of_the_leaf31 { + type string; + } + } + } + } + uses name_of_the_g1; + } + output { + container name_of_the_cont16 { + leaf name_of_the_leaf32 { + type string; + } + } + list name_of_the_list11 { + leaf name_of_the_leaf33 { + type string; + } + } + leaf name_of_the_leaf34 { + type string; + } + leaf-list name_of_the_ll11 { + type string; + } + choice name_of_the_ch4 { + case name_of_the_c1 { + container name_of_the_cont17 { + leaf name_of_the_leaf35 { + type string; + } + } + } + } + uses name_of_the_g1; + } + } + + container name_of_the_cont18 { + container name_of_the_cont18 { + list name_of_the_list12 { + list name_of_the_list12 { + leaf name_of_the_leaf36 { + type string; + } + } + leaf name_of_the_leaf36 { + type string; + } + } + } + leaf name_of_the_leaf40 { + type string; + } + } +}
\ No newline at end of file |