summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxudan16 <xudan16@huawei.com>2023-08-24 10:34:04 +0800
committerxudan16 <xudan16@huawei.com>2023-08-24 10:35:31 +0800
commit0ad6f5a18a6e5cc98f464cfcdb78130acb80d0e6 (patch)
tree4a1199d899f4f336414e6bc302d2b357d5fbb4b2
parent1c5d8057fb2fccdbc089d05e7c916725350a5ff8 (diff)
Yang Compiler for YANG Model automation
Issue-ID: MODELING-680 Change-Id: I191eef382c080525ec6b8827f8f1e0b4a82994a6 Signed-off-by: xudan16 <xudan16@huawei.com>
-rw-r--r--yang-compiler/pom.xml194
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/ModuleInfo.java130
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/YangCatalog.java143
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Authentication.java64
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Builder.java112
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/ParameterBuilder.java69
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginBuilder.java86
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginInfo.java188
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginParameterInfo.java59
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Proxy.java144
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Settings.java226
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompiler.java675
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompilerException.java33
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/app/YangCompilerRunner.java54
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPlugin.java74
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPluginParameter.java35
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangNodeDescription.java96
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangStatistics.java278
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/validator/YangValidator.java46
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/ModuleInfo.java117
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/PackageInfo.java45
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubComponentInfo.java171
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubModuleInfo.java125
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackage.java395
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageGenerator.java154
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageMeta.java187
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/GroupingSchemaNodeContainer.java141
-rw-r--r--yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/YangTreeGenerator.java654
28 files changed, 4695 insertions, 0 deletions
diff --git a/yang-compiler/pom.xml b/yang-compiler/pom.xml
new file mode 100644
index 0000000..cdd6626
--- /dev/null
+++ b/yang-compiler/pom.xml
@@ -0,0 +1,194 @@
+<?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.modeling.yangkit</groupId>
+ <artifactId>yangkit-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.onap.modeling.yangkit</groupId>
+ <artifactId>yang-compiler</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <properties>
+ <maven.compiler.source>8</maven.compiler.source>
+ <maven.compiler.target>8</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ <mainClass>org.onap.modeling.yangkit.compiler.app.YangCompilerRunner</mainClass>
+ <classpathPrefix>libs/</classpathPrefix>
+ </manifest>
+ <!--
+ <manifestEntries>
+ <Class-path>libs/yangkit-common-1.0-SNAPSHOT.jar libs/yangkit-common-utils-1.0-SNAPSHOT.jar libs/yangkit-data-api-1.0-SNAPSHOT.jar libs/yangkit-model-api-1.0-SNAPSHOT.jar libs/yangkit-model-impl-1.0-SNAPSHOT.jar libs/yangkit-parser-1.0-SNAPSHOT.jar libs/yangkit-xpath-api-1.0-SNAPSHOT.jar libs/yangkit-xpath-impl-1.0-SNAPSHOT.jar</Class-path>
+ </manifestEntries>-->
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.1.1</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>
+ ${project.build.directory}/libs
+ </outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>io.github.yang-central.yangkit</groupId>
+ <artifactId>yangkit-parser</artifactId>
+ <version>1.3.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jaxen</groupId>
+ <artifactId>jaxen</artifactId>
+ <version>2.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ <version>4.11.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>2.1.4</version>
+ </dependency>
+ <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.10.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi</artifactId>
+ <version>5.2.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi-ooxml</artifactId>
+ <version>5.2.3</version>
+ </dependency>
+ </dependencies>
+ <name>yang compiler</name>
+ <description>yang compiler: compile yang modules regardless where the dependencies are (by resolve and download
+ dependencies automatically)</description>
+ <profiles>
+ <profile>
+ <id>release</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ <useReleaseProfile>false</useReleaseProfile>
+ <releaseProfiles>release</releaseProfiles>
+ <goals>deploy</goals>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+<!--
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>3.4.0</version>
+ <configuration>
+ <source>8</source>
+ <detectJavaApiLink>false</detectJavaApiLink>
+ <locale>en_US</locale>
+ <charset>UTF-8</charset>
+ <encoding>UTF-8</encoding>
+ <docencoding>UTF-8</docencoding>
+
+ <doclet>ch.raffael.doclets.pegdown.PegdownDoclet</doclet>
+ <docletArtifact>
+ <groupId>ch.raffael.pegdown-doclet</groupId>
+ <artifactId>pegdown-doclet</artifactId>
+ <version>1.1</version>
+ </docletArtifact>
+ <useStandardDocletOptions>true</useStandardDocletOptions>
+ </configuration>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+-->
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/ModuleInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/ModuleInfo.java
new file mode 100644
index 0000000..31bb51e
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/ModuleInfo.java
@@ -0,0 +1,130 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.catalog;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.net.URI;
+
+
+public class ModuleInfo {
+ private final String name;
+ private final String revision;
+ private final String organization;
+ private URI schema;
+
+ /**
+ * The constructor of ModuleInfo.
+ * @param name module name
+ * @param revision module revision
+ * @param organization the organization who publish this module
+ */
+ public ModuleInfo(String name, String revision, String organization) {
+ this.name = name;
+ this.revision = revision;
+ this.organization = organization;
+ }
+
+ /**
+ * set schema.
+ * @param schema the URI of schema
+ */
+ public void setSchema(URI schema) {
+ this.schema = schema;
+ }
+
+ /**
+ * get module name.
+ * @return module name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get module's revision.
+ * @return revision
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * get organization.
+ * @return organization
+ */
+ public String getOrganization() {
+ return organization;
+ }
+
+ /**
+ * get schema.
+ * @return URI
+ */
+ public URI getSchema() {
+ return schema;
+ }
+
+ /**
+ * parse module info from json.
+ * @param element json element
+ * @return ModuleInfo
+ */
+ public static ModuleInfo parse(JsonElement element) {
+ JsonObject jsonObject = element.getAsJsonObject();
+ String name = jsonObject.get("name").getAsString();
+ String revision = jsonObject.get("revision").getAsString();
+ JsonElement organizationElement = jsonObject.get("organization");
+ String organization = null;
+ if (organizationElement != null) {
+ organization = organizationElement.getAsString();
+ }
+ JsonElement schemaElement = jsonObject.get("schema");
+ if (schemaElement == null) {
+ return null;
+ }
+ URI schema = URI.create(schemaElement.getAsString());
+ if (name == null || revision == null) {
+ return null;
+ }
+ ModuleInfo moduleInfo = new ModuleInfo(name,revision,organization);
+ moduleInfo.setSchema(schema);
+ return moduleInfo;
+ }
+
+ /**
+ * parse module information from json string.
+ * @param str json string
+ * @return Module information
+ */
+ public static ModuleInfo parse(String str) {
+ JsonElement element = JsonParser.parseString(str);
+ JsonObject modules = element.getAsJsonObject();
+ JsonElement moduleElement = modules.get("module");
+ if (moduleElement == null) {
+ return null;
+ }
+ JsonArray jsonArray = moduleElement.getAsJsonArray();
+ if (jsonArray.size() != 1) {
+ return null;
+ }
+ return parse(jsonArray.get(0));
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/YangCatalog.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/YangCatalog.java
new file mode 100644
index 0000000..21673c5
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/catalog/YangCatalog.java
@@ -0,0 +1,143 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.catalog;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class YangCatalog {
+ private final List<ModuleInfo> modules = new ArrayList<>();
+
+ /**
+ * add module information to yang catalog.
+ *
+ * @param moduleInfo module information structure
+ */
+ public void addModule(ModuleInfo moduleInfo) {
+ if (getModule(moduleInfo.getName(), moduleInfo.getRevision(), moduleInfo.getOrganization())
+ != null) {
+ return;
+ }
+ modules.add(moduleInfo);
+ }
+
+ /**
+ * get module information from yang catalog.
+ *
+ * @param name module name
+ * @param revision module revision
+ * @param organization the organization who publish the module
+ * @return module information
+ */
+ public ModuleInfo getModule(String name, String revision, String organization) {
+ if (modules.isEmpty()) {
+ return null;
+ }
+ for (ModuleInfo moduleInfo : modules) {
+ if (moduleInfo.getName().equals(name) && moduleInfo.getRevision().equals(revision)
+ && moduleInfo.getOrganization().equals(organization)) {
+ return moduleInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get all modules from yang catalog.
+ *
+ * @return list of modules
+ */
+ public List<ModuleInfo> getModules() {
+ return modules;
+ }
+
+ /**
+ * get all modules by module name.
+ *
+ * @param moduleName module name
+ * @return list of matched modules
+ */
+ public List<ModuleInfo> getModules(String moduleName) {
+ List<ModuleInfo> moduleInfos = new ArrayList<>();
+ for (ModuleInfo moduleInfo : modules) {
+ if (moduleInfo.getName().equals(moduleName)) {
+ moduleInfos.add(moduleInfo);
+ }
+ }
+ return moduleInfos;
+ }
+
+ /**
+ * get the latest module by module name.
+ *
+ * @param moduleName module name
+ * @return the latest module information
+ */
+ public ModuleInfo getLatestModule(String moduleName) {
+ List<ModuleInfo> matched = getModules(moduleName);
+ if (matched.isEmpty()) {
+ return null;
+ }
+ if (matched.size() == 1) {
+ return matched.get(0);
+ }
+ ModuleInfo latest = null;
+ for (ModuleInfo moduleInfo : matched) {
+ if (latest == null) {
+ latest = moduleInfo;
+ } else {
+ if (moduleInfo.getRevision().compareTo(latest.getRevision()) > 0) {
+ latest = moduleInfo;
+ }
+ }
+ }
+ return latest;
+ }
+
+ /**
+ * parse yang catalog from json string.
+ *
+ * @param str json string
+ * @return yang catalog
+ */
+ public static YangCatalog parse(String str) {
+ YangCatalog yangCatalog = new YangCatalog();
+ JsonElement element = JsonParser.parseString(str);
+ JsonObject jsonObject = element.getAsJsonObject();
+ JsonElement modulesElement = jsonObject.get("yang-catalog:modules");
+ JsonObject modules = modulesElement.getAsJsonObject();
+ JsonElement moduleElement = modules.get("module");
+ JsonArray moduleArray = moduleElement.getAsJsonArray();
+ int size = moduleArray.size();
+ for (int i = 0; i < size; i++) {
+ JsonElement subElement = moduleArray.get(i);
+ ModuleInfo moduleInfo = ModuleInfo.parse(subElement);
+ if (moduleInfo == null) {
+ continue;
+ }
+ yangCatalog.addModule(moduleInfo);
+ }
+ return yangCatalog;
+ }
+
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Authentication.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Authentication.java
new file mode 100644
index 0000000..4684a4d
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Authentication.java
@@ -0,0 +1,64 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+
+public class Authentication {
+ private final String name;
+ private final String password;
+
+ /**
+ * the constructor.
+ * @param name user name
+ * @param password password
+ */
+ public Authentication(String name, String password) {
+ this.name = name;
+ this.password = password;
+ }
+
+ /**
+ * get the username.
+ * @return user name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the password.
+ * @return password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * parse authentication from json element.
+ * @param jsonElement json element
+ * @return the structure of authentication
+ */
+ public static Authentication parse(JsonElement jsonElement) {
+ JsonObject authenticationObject = jsonElement.getAsJsonObject();
+ String name = authenticationObject.get("username").getAsString();
+ String passwd = authenticationObject.get("password").getAsString();
+ return new Authentication(name, passwd);
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Builder.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Builder.java
new file mode 100644
index 0000000..7436447
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Builder.java
@@ -0,0 +1,112 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Builder {
+ private String yangDir;
+ private List<PluginBuilder> plugins = new ArrayList<>();
+
+ /**
+ * the constructor.
+ */
+ public Builder() {
+ }
+
+ /**
+ * get yang directory where the yang files to be compiled exist.
+ *
+ * @return the directory path
+ */
+ public String getYangDir() {
+ return yangDir;
+ }
+
+ /**
+ * set the yang directory.
+ *
+ * @param yangDir the path of yang directory
+ */
+ public void setYangDir(String yangDir) {
+ this.yangDir = yangDir;
+ }
+
+ /**
+ * get the plugins.
+ *
+ * @return the list of plugins
+ */
+ public List<PluginBuilder> getPlugins() {
+ return plugins;
+ }
+
+ /**
+ * set the list of plugins.
+ *
+ * @param plugins the list of plugins
+ */
+ public void setPlugins(List<PluginBuilder> plugins) {
+ this.plugins = plugins;
+ }
+
+ /**
+ * add a plugin.
+ *
+ * @param pluginBuilder plugin to be added.
+ */
+ public void addPlugin(PluginBuilder pluginBuilder) {
+ this.plugins.add(pluginBuilder);
+ }
+
+ /**
+ * parse the build.json.
+ *
+ * @param jsonElement json element
+ * @return builder structure
+ */
+ public static Builder parse(JsonElement jsonElement) {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ JsonElement buildElement = jsonObject.get("build");
+ Builder builder = new Builder();
+ if (buildElement == null) {
+ return builder;
+ }
+ JsonObject buildObj = buildElement.getAsJsonObject();
+ JsonElement yangElement = buildObj.get("yang");
+ if (yangElement != null) {
+ String yang = yangElement.getAsString();
+ builder.setYangDir(yang);
+ }
+ JsonElement pluginsElement = buildObj.get("plugin");
+ if (pluginsElement != null) {
+ JsonArray plugins = pluginsElement.getAsJsonArray();
+ for (int i = 0; i < plugins.size(); i++) {
+ JsonElement pluginElement = plugins.get(i);
+ PluginBuilder pluginBuilder = PluginBuilder.parse(pluginElement);
+ builder.addPlugin(pluginBuilder);
+ }
+ }
+ return builder;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/ParameterBuilder.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/ParameterBuilder.java
new file mode 100644
index 0000000..ea8ad7a
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/ParameterBuilder.java
@@ -0,0 +1,69 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+
+public class ParameterBuilder {
+ private final String name;
+ private final String value;
+
+ /**
+ * the constructor.
+ *
+ * @param name the name of parameter
+ * @param value the value of parameter
+ */
+ public ParameterBuilder(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * get the parameter name.
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the parameter value.
+ *
+ * @return value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * parse parameter from json.
+ *
+ * @param jsonElement json element
+ * @return parameter
+ */
+ public static ParameterBuilder parse(JsonElement jsonElement) {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ String name = jsonObject.get("name").getAsString();
+ String value = jsonObject.get("value").getAsString();
+ ParameterBuilder parameterBuilder = new ParameterBuilder(name, value);
+ return parameterBuilder;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginBuilder.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginBuilder.java
new file mode 100644
index 0000000..489d1f7
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginBuilder.java
@@ -0,0 +1,86 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class PluginBuilder {
+ private final String name;
+ private final List<ParameterBuilder> parameters = new ArrayList<>();
+
+ /**
+ * the constructor.
+ *
+ * @param name the plugin name
+ */
+ public PluginBuilder(String name) {
+ this.name = name;
+ }
+
+ /**
+ * get the plugin name.
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get all parameters of plugin.
+ *
+ * @return the list of parameters
+ */
+ public List<ParameterBuilder> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * add parameter into plugin.
+ *
+ * @param para parameter
+ */
+ public void addParameter(ParameterBuilder para) {
+ parameters.add(para);
+ }
+
+ /**
+ * parse plugin from json.
+ *
+ * @param jsonElement json element
+ * @return plugin builder
+ */
+ public static PluginBuilder parse(JsonElement jsonElement) {
+ String name = jsonElement.getAsJsonObject().get("name").getAsString();
+ PluginBuilder pluginBuilder = new PluginBuilder(name);
+ JsonElement parasElement = jsonElement.getAsJsonObject().get("parameter");
+ if (parasElement != null) {
+ JsonArray paras = parasElement.getAsJsonArray();
+ for (int i = 0; i < paras.size(); i++) {
+ JsonElement paraElement = paras.get(i);
+ ParameterBuilder parameterBuilder = ParameterBuilder.parse(paraElement);
+ pluginBuilder.addParameter(parameterBuilder);
+ }
+ }
+ return pluginBuilder;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginInfo.java
new file mode 100644
index 0000000..a042dd0
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginInfo.java
@@ -0,0 +1,188 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+
+
+@SuppressWarnings("ALL")
+public class PluginInfo {
+ private final String pluginName;
+ private final YangCompilerPlugin plugin;
+
+ private String description;
+ private final List<PluginParameterInfo> parameters = new ArrayList<>();
+
+ /**
+ * the constructor.
+ *
+ * @param pluginName plugin name
+ * @param plugin plugin
+ */
+ public PluginInfo(String pluginName, YangCompilerPlugin plugin) {
+ this.pluginName = pluginName;
+ this.plugin = plugin;
+ }
+
+ /**
+ * get the name of plugin.
+ *
+ * @return name
+ */
+ public String getPluginName() {
+ return pluginName;
+ }
+
+ /**
+ * get the plugin.
+ *
+ * @return plugin
+ */
+ public YangCompilerPlugin getPlugin() {
+ return plugin;
+ }
+
+ /**
+ * get the description.
+ *
+ * @return description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * set the description.
+ *
+ * @param description description string
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * get the parameters of the plugin.
+ *
+ * @return the parameters
+ */
+ public List<PluginParameterInfo> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * add a parameter to plugin.
+ *
+ * @param parameter parameter
+ */
+ public void addParameter(PluginParameterInfo parameter) {
+ parameters.add(parameter);
+ }
+
+ /**
+ * parse plugin information from json.
+ *
+ * @param pluginFile plugins.json File handler
+ * @param jsonElement json element
+ * @return plugin information
+ */
+ public static PluginInfo parse(File pluginFile, JsonElement jsonElement) {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ String pluginName = jsonObject.get("name").getAsString();
+ String classPath = null;
+ JsonElement classPathElement = jsonObject.get("class-path");
+ if (classPathElement != null) {
+ classPath = classPathElement.getAsString();
+ }
+ String className = jsonObject.get("class").getAsString();
+ try {
+ Class<? extends YangCompilerPlugin> pluginClass = null;
+ if (classPath != null && !classPath.trim().isEmpty()) {
+ Path path = Paths.get(classPath);
+ File file;
+ if (!path.isAbsolute()) {
+ file = new File(pluginFile.getParentFile(), classPath);
+ } else {
+ file = new File(classPath);
+ }
+ if (!file.exists()) {
+ System.out.println("[ERROR]the class-path:" + file.getAbsolutePath() + " is not found.");
+ return null;
+ }
+ URL[] cp = {file.toURI().toURL()};
+ try (URLClassLoader classLoader = new URLClassLoader(cp)) {
+ pluginClass = (Class<? extends YangCompilerPlugin>) classLoader.loadClass(className);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ pluginClass = (Class<? extends YangCompilerPlugin>) Class.forName(className);
+ }
+
+ Constructor<? extends YangCompilerPlugin> constructor = pluginClass.getConstructor();
+ YangCompilerPlugin yangCompilerPlugin = constructor.newInstance();
+ PluginInfo pluginInfo = new PluginInfo(pluginName, yangCompilerPlugin);
+ if (jsonObject.get("description") != null) {
+ String description = jsonObject.get("description").getAsString();
+ pluginInfo.setDescription(description);
+ }
+ JsonElement parasElement = jsonObject.get("parameter");
+ if (parasElement != null) {
+ JsonArray paraArray = parasElement.getAsJsonArray();
+ for (int i = 0; i < paraArray.size(); i++) {
+ JsonElement paraElement = paraArray.get(i);
+ JsonObject para = paraElement.getAsJsonObject();
+ String name = para.get("name").getAsString();
+ PluginParameterInfo parameter = new PluginParameterInfo(name);
+ if (para.get("description") != null) {
+ String description = para.get("description").getAsString();
+ parameter.setDescription(description);
+ }
+ pluginInfo.addParameter(parameter);
+ }
+ }
+ return pluginInfo;
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginParameterInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginParameterInfo.java
new file mode 100644
index 0000000..526b94a
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/PluginParameterInfo.java
@@ -0,0 +1,59 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+
+public class PluginParameterInfo {
+ private final String name;
+ private String description;
+
+ /**
+ * the constructor.
+ *
+ * @param name parameter name
+ */
+ public PluginParameterInfo(String name) {
+ this.name = name;
+ }
+
+ /**
+ * get the parameter name.
+ *
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the description.
+ *
+ * @return description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * set the description.
+ *
+ * @param description the description to be set
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Proxy.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Proxy.java
new file mode 100644
index 0000000..db183bc
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Proxy.java
@@ -0,0 +1,144 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+
+public class Proxy {
+ private final String hostName;
+ private final int port;
+ private Authentication authentication;
+
+ /**
+ * the constructor.
+ *
+ * @param hostName the host name
+ * @param port the port number
+ */
+ public Proxy(String hostName, int port) {
+ this.hostName = hostName;
+ this.port = port;
+ }
+
+ /**
+ * the constructor.
+ *
+ * @param hostName the host name.
+ */
+
+ public Proxy(String hostName) {
+ this.hostName = hostName;
+ this.port = 80;
+ }
+
+ /**
+ * get the host name.
+ *
+ * @return host name.
+ */
+ public String getHostName() {
+ return hostName;
+ }
+
+ /**
+ * get the port number.
+ *
+ * @return port number.
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * get the authentication information.
+ *
+ * @return authentication information
+ */
+ public Authentication getAuthentication() {
+ return authentication;
+ }
+
+ /**
+ * set the authentication information.
+ *
+ * @param authentication authentication information.
+ */
+ public void setAuthentication(Authentication authentication) {
+ this.authentication = authentication;
+ }
+
+ /**
+ * create a proxy instance from url.
+ *
+ * @param url url
+ * @return proxy
+ */
+ public static Proxy create(URL url) {
+ return new Proxy(url.getHost(), url.getPort() == -1 ? url.getDefaultPort() : url.getPort());
+ }
+
+ /**
+ * parse proxy from json.
+ *
+ * @param jsonElement json element
+ * @return proxy
+ */
+ public static Proxy parse(JsonElement jsonElement) {
+ Proxy proxy = null;
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ JsonElement urlElement = jsonObject.get("url");
+ if (urlElement != null) {
+ String urlString = urlElement.getAsString();
+ try {
+ URL url = URI.create(urlString).toURL();
+ proxy = Proxy.create(url);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ JsonElement hostElement = jsonObject.get("host");
+ if (hostElement != null) {
+ String host = hostElement.getAsString();
+ int port = -1;
+ JsonElement portElement = jsonObject.get("port");
+ if (portElement != null) {
+ port = portElement.getAsInt();
+ }
+ if (port != -1) {
+ proxy = new Proxy(host, port);
+ } else {
+ proxy = new Proxy(host);
+ }
+ }
+ }
+ JsonElement authenticationElement = jsonObject.get("authentication");
+ if (authenticationElement != null) {
+ Authentication authentication = Authentication.parse(authenticationElement);
+ if (proxy != null) {
+ proxy.setAuthentication(authentication);
+ }
+
+ }
+ return proxy;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Settings.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Settings.java
new file mode 100644
index 0000000..7acb56b
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/Settings.java
@@ -0,0 +1,226 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onap.modeling.yangkit.catalog.ModuleInfo;
+
+
+public class Settings {
+ private URI remoteRepository = URI.create("https://yangcatalog.org/api/");
+ private String localRepository = System.getProperty("user.home") + File.separator + ".yang";
+
+ private Proxy proxy;
+
+ private String token;
+ private List<ModuleInfo> moduleInfos = new ArrayList<>();
+
+ /**
+ * get the remote repository.
+ *
+ * @return the URI
+ */
+ public URI getRemoteRepository() {
+ return remoteRepository;
+ }
+
+ /**
+ * set the remote repository.
+ *
+ * @param remoteRepository remote repository uri
+ */
+ public void setRemoteRepository(URI remoteRepository) {
+ this.remoteRepository = remoteRepository;
+ }
+
+ /**
+ * get the local repository.
+ *
+ * @return the path of local repository
+ */
+ public String getLocalRepository() {
+ return localRepository;
+ }
+
+ /**
+ * set the local repository.
+ *
+ * @param localRepository the path of local repository.
+ */
+ public void setLocalRepository(String localRepository) {
+ this.localRepository = localRepository;
+ }
+
+ /**
+ * get the information of modules.
+ *
+ * @return the list of module information
+ */
+ public List<ModuleInfo> getModuleInfos() {
+ return moduleInfos;
+ }
+
+ /**
+ * get the information of modules by module name.
+ *
+ * @param name module name
+ * @return the list of matched module information
+ */
+ public List<ModuleInfo> getModuleInfos(String name) {
+ List<ModuleInfo> matched = new ArrayList<>();
+ for (ModuleInfo moduleInfo : moduleInfos) {
+ if (moduleInfo.getName().equals(name)) {
+ matched.add(moduleInfo);
+ }
+ }
+ return matched;
+ }
+
+ /**
+ * get the latest module information by specified name.
+ *
+ * @param name module name
+ * @return the latest module information
+ */
+ public ModuleInfo getLatestModuleInfo(String name) {
+ List<ModuleInfo> matched = getModuleInfos(name);
+ ModuleInfo latest = null;
+ for (ModuleInfo moduleInfo : matched) {
+ if (latest == null) {
+ latest = moduleInfo;
+ } else {
+ if (moduleInfo.getRevision().compareTo(latest.getRevision()) > 0) {
+ latest = moduleInfo;
+ }
+ }
+ }
+ return latest;
+ }
+
+ /**
+ * get the module information by specified module name and revision.
+ *
+ * @param name module name
+ * @param revision module revision
+ * @return the matched module information
+ */
+ public ModuleInfo getModuleInfo(String name, String revision) {
+ for (ModuleInfo moduleInfo : moduleInfos) {
+ if (moduleInfo.getName().equals(name)
+ && moduleInfo.getRevision().equals(revision)) {
+ return moduleInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get the proxy.
+ *
+ * @return proxy
+ */
+ public Proxy getProxy() {
+ return proxy;
+ }
+
+ /**
+ * set proxy.
+ *
+ * @param proxy proxy
+ */
+ public void setProxy(Proxy proxy) {
+ this.proxy = proxy;
+ }
+
+ /**
+ * get token.
+ *
+ * @return token string
+ */
+ public String getToken() {
+ return token;
+ }
+
+ /**
+ * set token.
+ *
+ * @param token token
+ */
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ /**
+ * parse settings from json string.
+ *
+ * @param str json string
+ * @return settings
+ */
+ public static Settings parse(String str) {
+ Settings settings = new Settings();
+ JsonElement element = JsonParser.parseString(str);
+ if (element == null) {
+ return settings;
+ }
+ JsonObject jsonObject = element.getAsJsonObject();
+ JsonObject settingInstance = jsonObject.get("settings").getAsJsonObject();
+ JsonElement localElement = settingInstance.get("local-repository");
+ if (localElement != null) {
+ String localRepository = localElement.getAsString();
+ if (null != localRepository) {
+ settings.setLocalRepository(localRepository);
+ }
+ }
+ JsonElement remoteElement = settingInstance.get("remote-repository");
+ if (remoteElement != null) {
+ String remoteRepository = remoteElement.getAsString();
+ if (null != remoteRepository) {
+ settings.setRemoteRepository(URI.create(remoteRepository));
+ }
+ }
+
+ JsonElement proxyElement = settingInstance.get("proxy");
+ if (proxyElement != null) {
+ Proxy proxy = Proxy.parse(proxyElement);
+ settings.setProxy(proxy);
+ }
+ JsonElement tokenElement = settingInstance.get("token");
+ if (tokenElement != null) {
+ settings.setToken(tokenElement.getAsString());
+ }
+ JsonElement moduleInfosElement = settingInstance.get("module-info");
+ if (moduleInfosElement != null) {
+ JsonArray moduleInfos = moduleInfosElement.getAsJsonArray();
+ for (int i = 0; i < moduleInfos.size(); i++) {
+ JsonElement moduleElement = moduleInfos.get(i);
+ ModuleInfo moduleInfo = ModuleInfo.parse(moduleElement);
+ settings.moduleInfos.add(moduleInfo);
+ }
+ }
+
+ return settings;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompiler.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompiler.java
new file mode 100644
index 0000000..7d4975d
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompiler.java
@@ -0,0 +1,675 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Authenticator;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.Proxy;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Scanner;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.Nullable;
+
+
+import org.dom4j.DocumentException;
+import org.onap.modeling.yangkit.catalog.ModuleInfo;
+import org.onap.modeling.yangkit.catalog.YangCatalog;
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+import org.onap.modeling.yangkit.plugin.YangCompilerPluginParameter;
+import org.yangcentral.yangkit.base.YangBuiltinKeyword;
+import org.yangcentral.yangkit.base.YangElement;
+import org.yangcentral.yangkit.common.api.validate.ValidatorRecord;
+import org.yangcentral.yangkit.common.api.validate.ValidatorResult;
+import org.yangcentral.yangkit.common.api.validate.ValidatorResultBuilder;
+import org.yangcentral.yangkit.model.api.schema.ModuleId;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+import org.yangcentral.yangkit.model.api.stmt.Module;
+import org.yangcentral.yangkit.model.api.stmt.SubModule;
+import org.yangcentral.yangkit.model.api.stmt.YangStatement;
+import org.yangcentral.yangkit.parser.YangParser;
+import org.yangcentral.yangkit.parser.YangParserEnv;
+import org.yangcentral.yangkit.parser.YangParserException;
+import org.yangcentral.yangkit.parser.YangYinParser;
+import org.yangcentral.yangkit.utils.file.FileUtil;
+import org.yangcentral.yangkit.utils.url.URLUtil;
+import org.yangcentral.yangkit.writter.YangFormatter;
+import org.yangcentral.yangkit.writter.YangWriter;
+
+
+public class YangCompiler {
+
+ private Settings settings;
+ private File yang;
+
+ private final Map<String, PluginInfo> pluginInfos = new ConcurrentHashMap<String, PluginInfo>();
+
+ private Builder builder;
+
+ /**
+ * constructor.
+ */
+ public YangCompiler() {
+ }
+
+ /**
+ * get the builder.
+ *
+ * @return builder class
+ */
+ public Builder getBuilder() {
+ return builder;
+ }
+
+ /**
+ * set builder.
+ *
+ * @param builder builder
+ */
+ public void setBuilder(Builder builder) {
+ this.builder = builder;
+ }
+
+ /**
+ * get plugin information.
+ *
+ * @param name plugin name
+ * @return plugin information
+ */
+ public PluginInfo getPluginInfo(String name) {
+ if (pluginInfos.isEmpty()) {
+ return null;
+ }
+ return pluginInfos.get(name);
+ }
+
+ /**
+ * add a new plugin.
+ *
+ * @param pluginInfo plugin information
+ */
+ public void addPluginInfo(PluginInfo pluginInfo) {
+ if (pluginInfo == null) {
+ return;
+ }
+ if (getPluginInfo(pluginInfo.getPluginName()) != null) {
+ return;
+ }
+ pluginInfos.put(pluginInfo.getPluginName(), pluginInfo);
+ }
+
+ /**
+ * get settings.
+ *
+ * @return settings
+ */
+ public Settings getSettings() {
+ return settings;
+ }
+
+ /**
+ * set settings.
+ *
+ * @param settings settings
+ */
+ public void setSettings(Settings settings) {
+ this.settings = settings;
+ }
+
+ /**
+ * get yang directory file handler.
+ *
+ * @return yang directory file handler.
+ */
+ public File getYang() {
+ return yang;
+ }
+
+ /**
+ * set yang directory file handler.
+ *
+ * @param yang file handler
+ */
+ public void setYang(File yang) {
+ this.yang = yang;
+ }
+
+ /**
+ * get all dependencies of a specified module.
+ *
+ * @param module module
+ * @return dependencies
+ */
+ private List<ModuleId> getDependencies(Module module) {
+ List<ModuleId> dependencies = new ArrayList<>();
+ if (module == null) {
+ return dependencies;
+ }
+ List<YangStatement> importStatements = module.getSubStatement(YangBuiltinKeyword.IMPORT.getQName());
+ for (YangStatement importStatement : importStatements) {
+ String moduleName = importStatement.getArgStr();
+ String revision = null;
+ List<YangStatement> revisions = importStatement.getSubStatement(YangBuiltinKeyword.REVISIONDATE.getQName());
+ if (revisions.isEmpty()) {
+ revision = "";
+ } else {
+ revision = revisions.get(0).getArgStr();
+ }
+ ModuleId moduleId = new ModuleId(moduleName, revision);
+ dependencies.add(moduleId);
+ }
+ List<YangStatement> includeStatements = module.getSubStatement(YangBuiltinKeyword.INCLUDE.getQName());
+ for (YangStatement includeStatement : includeStatements) {
+ String moduleName = includeStatement.getArgStr();
+ String revision = null;
+ List<YangStatement> revisions =
+ includeStatement.getSubStatement(YangBuiltinKeyword.REVISIONDATE.getQName());
+ if (revisions.isEmpty()) {
+ revision = "";
+ } else {
+ revision = revisions.get(0).getArgStr();
+ }
+ ModuleId moduleId = new ModuleId(moduleName, revision);
+ dependencies.add(moduleId);
+ }
+ if (module instanceof SubModule) {
+ List<YangStatement> belongsToStatements = module.getSubStatement(YangBuiltinKeyword.BELONGSTO.getQName());
+ String moduleName = belongsToStatements.get(0).getArgStr();
+ ModuleId moduleId = new ModuleId(moduleName, "");
+ dependencies.add(moduleId);
+ }
+ return dependencies;
+ }
+
+ private String urlInvoke(String url) throws IOException {
+ URL catalogUrl = URI.create(url).toURL();
+ Proxy proxy = null;
+ Authenticator authenticator = null;
+ if (settings.getProxy() != null) {
+ String protocol = catalogUrl.getProtocol();
+ Proxy.Type proxyType = null;
+ if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) {
+ proxyType = Proxy.Type.HTTP;
+ } else {
+ proxyType = Proxy.Type.SOCKS;
+ }
+ proxy = new Proxy(proxyType,
+ new InetSocketAddress(settings.getProxy().getHostName(), settings.getProxy().getPort()));
+ if (settings.getProxy().getAuthentication() != null) {
+ authenticator = new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(settings.getProxy().getAuthentication().getName(),
+ settings.getProxy().getAuthentication().getPassword().toCharArray()
+ );
+ }
+ };
+ Authenticator.setDefault(authenticator);
+ }
+
+ }
+ return URLUtil.URLGet(catalogUrl, proxy, authenticator, settings.getToken());
+ }
+
+ private File getFromLocal(ModuleId moduleId) {
+ File localRepository = new File(settings.getLocalRepository());
+ if (!localRepository.exists()) {
+ localRepository.mkdirs();
+ }
+ String prefix =
+ moduleId.getModuleName() + (moduleId.getRevision().equals("") ? "" : "@" + moduleId.getRevision());
+ String suffix = ".yang";
+ FilenameFilter filenameFilter = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ if (dir != localRepository) {
+ return false;
+ }
+ if (name.startsWith(prefix) && name.endsWith(suffix)) {
+ String moduleDesc = name.substring(0, name.indexOf(suffix));
+ String[] moduleInfo = moduleDesc.split("@");
+ String moduleName = moduleInfo[0];
+ String revision = moduleInfo[1];
+ if (!moduleName.equals(moduleId.getModuleName())) {
+ return false;
+ }
+ if (moduleId.getRevision() != null && moduleId.getRevision().length() > 0) {
+ if (!revision.equals(moduleId.getRevision())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+ System.out.print("[INFO]finding module:" + moduleId.getModuleName()
+ + (moduleId.getRevision().isEmpty() ? "" : moduleId.getRevision())
+ + " from " + localRepository.getAbsolutePath()
+ + " ...");
+ File[] matched = localRepository.listFiles(filenameFilter);
+ if (matched == null || matched.length == 0) {
+ System.out.println("not found.");
+ return null;
+ }
+ if (matched.length == 1) {
+ System.out.println("get " + matched[0].getName());
+ return matched[0];
+ }
+ File latest = null;
+ if (matched.length > 1) {
+ for (File file : matched) {
+ if (latest == null) {
+ latest = file;
+ } else {
+ if (file.getName().compareTo(latest.getName()) > 0) {
+ latest = file;
+ }
+ }
+ }
+ }
+ System.out.println("get " + latest.getName());
+ return latest;
+ }
+
+ private File getFromRemote(ModuleId moduleId) throws IOException {
+ ModuleInfo moduleInfo = null;
+ if (moduleId.getRevision() == null || moduleId.getRevision().equals("")) {
+ String url = settings.getRemoteRepository() + "search/name/" + moduleId.getModuleName();
+ System.out.print("[INFO]downloading module info:" + moduleId.getModuleName() + " from " + url + " ...");
+ YangCatalog yangCatalog = YangCatalog.parse(urlInvoke(url));
+ moduleInfo = yangCatalog.getLatestModule(moduleId.getModuleName());
+ System.out.println(moduleInfo == null ? " not found." : "revision=" + moduleInfo.getRevision());
+
+ } else {
+ String organization = moduleId.getModuleName().substring(0, moduleId.getModuleName().indexOf("-"));
+ if (organization.equals("junos")) {
+ organization = "juniper";
+ }
+ String url = settings.getRemoteRepository()
+ + "search/modules/"
+ + moduleId.getModuleName()
+ + ","
+ + moduleId.getRevision()
+ + ","
+ + organization;
+ System.out.print("[INFO]downloading module info:"
+ + moduleId.getModuleName()
+ + " from "
+ + url
+ + " ...");
+ moduleInfo = ModuleInfo.parse(urlInvoke(url));
+ System.out.println(moduleInfo == null ? " not found." : "finished");
+
+ }
+ if (moduleInfo == null) {
+ return null;
+ }
+ System.out.print("[INFO]downloading content of module:" + moduleInfo.getName() + "@" + moduleInfo.getRevision()
+ + " from " + moduleInfo.getSchema().toString() + " ...");
+ String yangString = urlInvoke(moduleInfo.getSchema().toString());
+ System.out.println("finished.");
+ File localRepositoryFile = new File(settings.getLocalRepository());
+ if (!localRepositoryFile.exists()) {
+ localRepositoryFile.mkdirs();
+ }
+ String yangfileName = moduleInfo.getName() + "@" + moduleInfo.getRevision() + ".yang";
+ File localYangFile = new File(localRepositoryFile, yangfileName);
+ FileUtil.writeUtf8File(yangString, localYangFile);
+ System.out.println("[INFO]save module:"
+ + moduleInfo.getName()
+ + "@"
+ + moduleInfo.getRevision()
+ + " to "
+ + localYangFile.getAbsolutePath());
+ return localYangFile;
+ }
+
+ private File getFromSettings(ModuleId moduleId) throws IOException {
+ ModuleInfo moduleInfo = null;
+ if (moduleId.getRevision() == null || moduleId.getRevision().equals("")) {
+ moduleInfo = settings.getLatestModuleInfo(moduleId.getModuleName());
+ System.out.print("[INFO]getting module info:"
+ + moduleId.getModuleName()
+ + " from settings");
+ System.out.println(moduleInfo == null ? " not found." : "revision="
+ + moduleInfo.getRevision());
+
+ } else {
+ System.out.print("[INFO]getting module info:"
+ + moduleId.getModuleName()
+ + " from settings.");
+ moduleInfo = settings.getModuleInfo(moduleId.getModuleName(), moduleId.getRevision());
+ System.out.println(moduleInfo == null ? " not found." : "finished");
+
+ }
+ if (moduleInfo == null) {
+ return null;
+ }
+ System.out.print("[INFO]downloading content of module:"
+ + moduleInfo.getName()
+ + "@"
+ + moduleInfo.getRevision()
+ + " from "
+ + moduleInfo.getSchema().toString()
+ + " ...");
+ String yangString = urlInvoke(moduleInfo.getSchema().toString());
+ System.out.println("finished.");
+ File localRepositoryFile = new File(settings.getLocalRepository());
+ if (!localRepositoryFile.exists()) {
+ localRepositoryFile.mkdirs();
+ }
+ String yangfileName = moduleInfo.getName()
+ + "@"
+ + moduleInfo.getRevision()
+ + ".yang";
+ File localYangFile = new File(localRepositoryFile, yangfileName);
+ FileUtil.writeUtf8File(yangString, localYangFile);
+ System.out.println("[INFO]save module:"
+ + moduleInfo.getName()
+ + "@"
+ + moduleInfo.getRevision()
+ + " to "
+ + localYangFile.getAbsolutePath());
+ return localYangFile;
+ }
+
+ private void buildDependencies(YangSchemaContext schemaContext, List<ModuleId> dependencies)
+ throws IOException, YangParserException, YangCompilerException {
+ for (ModuleId moduleId : dependencies) {
+ if (schemaContext.getModule(moduleId).isPresent()) {
+ continue;
+ }
+ //firstly,get yang file from local repository
+ File file = getFromLocal(moduleId);
+ if (file == null) {
+ //secondly,if not found,get yang file from settings
+ file = getFromSettings(moduleId);
+ if (file == null) {
+ //thirdly, if not found, get yang file from remote repository
+ file = getFromRemote(moduleId);
+ }
+ }
+ if (file == null) {
+ throw new YangCompilerException("can not find the yang module named:"
+ + moduleId.getModuleName(),
+ moduleId);
+ }
+
+ YangParserEnv env = new YangParserEnv();
+ env.setCurPos(0);
+ env.setYangStr(FileUtil.readFile2String(file));
+ env.setFilename(file.getAbsolutePath());
+ YangParser yangParser = new YangParser();
+ List<YangElement> yangElements = yangParser.parseYang(env.getYangStr(), env);
+ schemaContext.getParseResult().put(env.getFilename(), yangElements);
+ Module module = null;
+ for (YangElement yangElement : yangElements) {
+ if (yangElement instanceof Module) {
+ module = (Module) yangElement;
+ schemaContext.addImportOnlyModule(module);
+ break;
+ }
+ }
+ if (module != null) {
+ List<ModuleId> subDependencies = getDependencies(module);
+ if (!subDependencies.isEmpty()) {
+ buildDependencies(schemaContext, subDependencies);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * build yang schema context.
+ *
+ * @return yang schema context
+ */
+ public YangSchemaContext buildSchemaContext() {
+ if (!yang.exists()) {
+ return null;
+ }
+ try {
+ YangSchemaContext schemaContext = YangYinParser.parse(yang);
+ for (Module module : schemaContext.getModules()) {
+ List<ModuleId> dependencies = getDependencies(module);
+ buildDependencies(schemaContext, dependencies);
+ }
+ return schemaContext;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (YangParserException e) {
+ throw new RuntimeException(e);
+ } catch (DocumentException e) {
+ throw new RuntimeException(e);
+ } catch (YangCompilerException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * compile yang files.
+ *
+ * @param yangdir yang directory
+ * @param settingsfile the path of settings.json
+ * @param install whether install to local repository
+ * @throws IOException io exception
+ * @throws URISyntaxException uri syntax exception
+ */
+ public void compile(@Nullable String yangdir, @Nullable String settingsfile, boolean install)
+ throws IOException, URISyntaxException {
+ String defaultSettingsfile =
+ System.getProperty("user.home")
+ + File.separator
+ + ".yang"
+ + File.separator
+ + "settings.json";
+ Settings settings = null;
+ if (settingsfile != null) {
+ settings = Settings.parse(FileUtil.readFile2String(settingsfile));
+ } else {
+ File defaultSettingsFile = new File(defaultSettingsfile);
+ if (defaultSettingsFile.exists()) {
+ settings = Settings.parse(FileUtil.readFile2String(defaultSettingsfile));
+ } else {
+ File programDir = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation()
+ .toURI());
+ File programSettings = new File(programDir.getParentFile(), "settings.json");
+ if (programSettings.exists()) {
+ settings = Settings.parse(FileUtil.readFile2String(programSettings));
+ } else {
+ settings = new Settings();
+ }
+
+ }
+ }
+
+ setSettings(settings);
+ File builderFile = new File("build.json");
+ if (builderFile.exists()) {
+ Builder builder = prepareBuilder(FileUtil.readFile2String(builderFile));
+ setBuilder(builder);
+ if (yangdir == null) {
+ yangdir = builder.getYangDir();
+ }
+ }
+ if (yangdir == null) {
+ yangdir = "yang";
+ //System.out.println("no yang directory!");
+ //System.out.println("Usage: yang-compiler yang={yang directory} [settings={settings.json}] [install]");
+ //return;
+ }
+ File yangDirFile = new File(yangdir);
+ if (!yangDirFile.exists()) {
+ System.out.println("yang directory:"
+ + yangdir
+ + " is not exist!");
+ return;
+ }
+ setYang(new File(yangdir));
+ Properties compilerProps = new Properties();
+ compilerProps.setProperty("yang", yangdir);
+ if (settings.getLocalRepository() != null) {
+ compilerProps.setProperty("local-repository", settings.getLocalRepository());
+ }
+
+ if (settings.getRemoteRepository() != null) {
+ compilerProps.setProperty("remote-repository", settings.getRemoteRepository().toString());
+ }
+
+ preparePlugins(this);
+
+ YangSchemaContext schemaContext = buildSchemaContext();
+ ValidatorResult validatorResult = schemaContext.validate();
+ if (!validatorResult.isOk()) {
+ System.out.println(validatorResult);
+ return;
+ }
+ if (getBuilder() != null) {
+ for (PluginBuilder pluginBuilder : getBuilder().getPlugins()) {
+ PluginInfo pluginInfo = getPluginInfo(pluginBuilder.getName());
+ if (null == pluginInfo) {
+ System.out.println("can not find a plugin named:"
+ + pluginBuilder.getName());
+ continue;
+ }
+ YangCompilerPlugin plugin = pluginInfo.getPlugin();
+ try {
+ List<YangCompilerPluginParameter> parameters = new ArrayList<>();
+ if (!pluginBuilder.getParameters().isEmpty()) {
+ for (ParameterBuilder parameterBuilder : pluginBuilder.getParameters()) {
+ YangCompilerPluginParameter parameter = plugin.getParameter(compilerProps,
+ parameterBuilder.getName(), parameterBuilder.getValue());
+ if (parameter != null) {
+ parameters.add(parameter);
+ }
+ }
+ }
+ System.out.println("[INFO]call plugin:"
+ + pluginInfo.getPluginName()
+ + " ...");
+ plugin.run(schemaContext, this, parameters);
+ System.out.println("ok.");
+ } catch (YangCompilerException e) {
+ System.out.println("[ERROR]"
+ + e.getMessage());
+ }
+ }
+ }
+ ValidatorResultBuilder validatorResultBuilder = new ValidatorResultBuilder();
+ List<ValidatorRecord<?, ?>> records = validatorResult.getRecords();
+ for (ValidatorRecord<?, ?> record : records) {
+ if (record.getBadElement() instanceof YangStatement) {
+ YangStatement yangStatement = (YangStatement) record.getBadElement();
+ if (schemaContext.getModules().contains(yangStatement.getContext().getCurModule())) {
+ validatorResultBuilder.addRecord(record);
+ }
+ }
+ }
+ validatorResult = validatorResultBuilder.build();
+ if (install && validatorResult.isOk()) {
+ for (Module module : schemaContext.getModules()) {
+ List<YangElement> elements =
+ schemaContext.getParseResult().get(module.getElementPosition().getSource());
+ StringBuilder sb = new StringBuilder();
+ for (YangElement element : elements) {
+ String yangStr = YangWriter.toYangString(element, YangFormatter.getPrettyYangFormatter(), null);
+ sb.append(yangStr);
+ sb.append("\n");
+ }
+ String moduleDesc = module.getArgStr()
+ + (module.getCurRevisionDate().isPresent() ? "@" + module.getCurRevisionDate().get() : "");
+ String fileName = settings.getLocalRepository()
+ + File.separator + moduleDesc;
+ FileUtil.writeUtf8File(fileName, sb.toString());
+ System.out.println("[INFO]install "
+ + moduleDesc
+ + " to "
+ + settings.getLocalRepository());
+
+ }
+ }
+ System.out.println(validatorResult);
+ }
+
+ private static void preparePlugins(YangCompiler yangCompiler) throws IOException, URISyntaxException {
+ InputStream inputStream = yangCompiler.getClass().getResourceAsStream("/plugins.json");
+ Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
+ String result = scanner.hasNext() ? scanner.next() : "";
+ if (!result.isEmpty()) {
+ List<PluginInfo> pluginInfos = parsePlugins(null, result);
+ for (PluginInfo pluginInfo : pluginInfos) {
+ yangCompiler.addPluginInfo(pluginInfo);
+ }
+ }
+ File programDir = new File(yangCompiler.getClass().getProtectionDomain().getCodeSource().getLocation()
+ .toURI());
+ File pluginsDir = new File(programDir.getParentFile(), "plugins");
+ if (!pluginsDir.exists()) {
+ System.out.println("[WARNING]plugins dir:"
+ + pluginsDir.getAbsolutePath()
+ + " is not exists");
+ return;
+ }
+ File pluginsFile = new File(pluginsDir, "plugins.json");
+ if (pluginsFile.exists()) {
+ System.out.println("[INFO]reading the information of plugins from:"
+ + pluginsFile.getAbsolutePath());
+ List<PluginInfo> pluginInfos = parsePlugins(pluginsFile, FileUtil.readFile2String(pluginsFile));
+ for (PluginInfo pluginInfo : pluginInfos) {
+ yangCompiler.addPluginInfo(pluginInfo);
+ }
+ }
+
+
+ }
+
+ private static List<PluginInfo> parsePlugins(File pluginsFile, String str) {
+ List<PluginInfo> pluginInfos = new ArrayList<>();
+ JsonElement pluginsElement = JsonParser.parseString(str);
+ JsonObject jsonObject = pluginsElement.getAsJsonObject();
+ JsonObject pluginsObject = jsonObject.get("plugins").getAsJsonObject();
+ JsonArray pluginList = pluginsObject.getAsJsonArray("plugin");
+ for (int i = 0; i < pluginList.size(); i++) {
+ JsonElement pluginElement = pluginList.get(i);
+ PluginInfo pluginInfo = PluginInfo.parse(pluginsFile, pluginElement);
+ pluginInfos.add(pluginInfo);
+ }
+ return pluginInfos;
+ }
+
+ private static Builder prepareBuilder(String str) {
+ JsonElement jsonElement = JsonParser.parseString(str);
+ return Builder.parse(jsonElement);
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompilerException.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompilerException.java
new file mode 100644
index 0000000..b3d18e5
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/YangCompilerException.java
@@ -0,0 +1,33 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler;
+
+import org.yangcentral.yangkit.model.api.schema.ModuleId;
+
+
+public class YangCompilerException extends Exception{
+ private ModuleId module;
+
+ public YangCompilerException(String message, ModuleId module) {
+ super(message);
+ this.module = module;
+ }
+
+ public YangCompilerException(String message) {
+ super(message);
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/app/YangCompilerRunner.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/app/YangCompilerRunner.java
new file mode 100644
index 0000000..650e444
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/compiler/app/YangCompilerRunner.java
@@ -0,0 +1,54 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.compiler.app;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+
+
+public class YangCompilerRunner {
+ /**
+ * the main method of yang compiler runner.
+ * @param args arguments
+ * @throws IOException io exception
+ * @throws URISyntaxException uri syntax exception
+ */
+ public static void main(String[] args) throws IOException, URISyntaxException {
+ String yangdir = null;
+ String settingsfile = null;
+ boolean install = false;
+ for (String arg : args) {
+ String[] paras = arg.split("=");
+ if (paras.length == 2) {
+ String para = paras[0];
+ String value = paras[1];
+ if (para.equals("yang")) {
+ yangdir = value;
+ } else if (para.equals("settings")) {
+ settingsfile = value;
+ }
+ } else {
+ if (arg.equals("install")) {
+ install = true;
+ }
+ }
+ }
+ YangCompiler compiler = new YangCompiler();
+ compiler.compile(yangdir, settingsfile, install);
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPlugin.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPlugin.java
new file mode 100644
index 0000000..a30f9fc
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPlugin.java
@@ -0,0 +1,74 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+
+
+public interface YangCompilerPlugin {
+ /**
+ * default implementation of get parameter method.
+ * @param compilerProps the properties of yang compiler.
+ * @param name the name of parameter
+ * @param value the value of parameter
+ * @return yang compiler plugin parameter
+ * @throws YangCompilerException if error occurs, the exception will be thrown.
+ */
+ default YangCompilerPluginParameter getParameter(Properties compilerProps, String name, String value)
+ throws YangCompilerException {
+ YangCompilerPluginParameter yangCompilerPluginParameter = new YangCompilerPluginParameter() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Object getValue() {
+ Iterator<Map.Entry<Object, Object>> it = compilerProps.entrySet().iterator();
+ String formatStr = value;
+ while (it.hasNext()) {
+ Map.Entry<Object, Object> entry = it.next();
+ formatStr = formatStr.replaceAll("\\{" + entry.getKey() + "\\}",
+ Matcher.quoteReplacement((String) entry.getValue()));
+ }
+ return formatStr;
+
+ }
+
+ };
+ return yangCompilerPluginParameter;
+ }
+
+ /**
+ * the definition of run method.
+ * @param schemaContext yang schema context
+ * @param yangCompiler yang compiler instance
+ * @param parameters parameters
+ * @throws YangCompilerException if error occurs, the exception will be thrown.
+ */
+ void run(YangSchemaContext schemaContext, YangCompiler yangCompiler, List<YangCompilerPluginParameter> parameters)
+ throws YangCompilerException;
+
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPluginParameter.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPluginParameter.java
new file mode 100644
index 0000000..f3cb7aa
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/YangCompilerPluginParameter.java
@@ -0,0 +1,35 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin;
+
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+
+
+public interface YangCompilerPluginParameter {
+ /**
+ * get parameter name.
+ * @return name
+ */
+ String getName();
+
+ /**
+ * get parameter value.
+ * @return value
+ * @throws YangCompilerException yang compiler exception
+ */
+ Object getValue() throws YangCompilerException;
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangNodeDescription.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangNodeDescription.java
new file mode 100644
index 0000000..2a903ca
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangNodeDescription.java
@@ -0,0 +1,96 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.stat;
+
+
+public class YangNodeDescription {
+ private String path;
+ private String description;
+ private String config;
+ private String schemaType;
+ private String nodeType;
+ private String module;
+ private boolean isActive;
+ private boolean isDeviated;
+
+ public YangNodeDescription() {
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getConfig() {
+ return config;
+ }
+
+ public void setConfig(String config) {
+ this.config = config;
+ }
+
+ public String getSchemaType() {
+ return schemaType;
+ }
+
+ public void setSchemaType(String schemaType) {
+ this.schemaType = schemaType;
+ }
+
+ public String getNodeType() {
+ return nodeType;
+ }
+
+ public void setNodeType(String nodeType) {
+ this.nodeType = nodeType;
+ }
+
+ public String getModule() {
+ return module;
+ }
+
+ public void setModule(String module) {
+ this.module = module;
+ }
+
+ public boolean isActive() {
+ return isActive;
+ }
+
+ public void setActive(boolean active) {
+ isActive = active;
+ }
+
+ public boolean isDeviated() {
+ return isDeviated;
+ }
+
+ public void setDeviated(boolean deviated) {
+ isDeviated = deviated;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangStatistics.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangStatistics.java
new file mode 100644
index 0000000..f5863cc
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/stat/YangStatistics.java
@@ -0,0 +1,278 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.stat;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.xssf.streaming.SXSSFCell;
+import org.apache.poi.xssf.streaming.SXSSFRow;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+import org.onap.modeling.yangkit.plugin.YangCompilerPluginParameter;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+import org.yangcentral.yangkit.model.api.stmt.Module;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNode;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNodeContainer;
+import org.yangcentral.yangkit.model.api.stmt.SubModule;
+import org.yangcentral.yangkit.model.api.stmt.TypedDataNode;
+import org.yangcentral.yangkit.model.api.stmt.VirtualSchemaNode;
+
+
+public class YangStatistics implements YangCompilerPlugin {
+ /**
+ * get node description.
+ * @param schemaNode schema node
+ * @return node description
+ */
+ public YangNodeDescription getNodeDescription(SchemaNode schemaNode) {
+ if (schemaNode == null) {
+ return null;
+ }
+ if (schemaNode instanceof VirtualSchemaNode) {
+ return null;
+ }
+ if (schemaNode.getSchemaPath() == null) {
+ return null;
+ }
+ YangNodeDescription nodeDescription = new YangNodeDescription();
+ nodeDescription.setPath(schemaNode.getSchemaPath().toString());
+ nodeDescription.setDescription(
+ schemaNode.getDescription() == null ? "" : schemaNode.getDescription().getArgStr());
+ nodeDescription.setConfig(schemaNode.isConfig() ? "true" : "false");
+ nodeDescription.setSchemaType(schemaNode.getYangKeyword().getLocalName());
+ if (schemaNode instanceof TypedDataNode) {
+ TypedDataNode typedDataNode = (TypedDataNode) schemaNode;
+ nodeDescription.setNodeType(typedDataNode.getType().getArgStr());
+ }
+ nodeDescription.setModule(schemaNode.getContext().getCurModule().getArgStr());
+ nodeDescription.setActive(schemaNode.isActive());
+ nodeDescription.setDeviated(schemaNode.isDeviated());
+ return nodeDescription;
+ }
+
+ /**
+ * get node description for schema node container.
+ * @param schemaNodeContainer schema node container
+ * @return list of node description.
+ */
+ public List<YangNodeDescription> getNodeDescriptions(SchemaNodeContainer schemaNodeContainer) {
+ if (schemaNodeContainer == null) {
+ return new ArrayList<>();
+ }
+ List<YangNodeDescription> nodeDescriptions = new ArrayList<>();
+ if (schemaNodeContainer instanceof SchemaNode) {
+ SchemaNode schemaNode = (SchemaNode) schemaNodeContainer;
+ YangNodeDescription nodeDescription = getNodeDescription(schemaNode);
+ if (nodeDescription != null) {
+ nodeDescriptions.add(nodeDescription);
+ }
+ }
+
+ for (SchemaNode schemaNode : schemaNodeContainer.getSchemaNodeChildren()) {
+ if (schemaNode instanceof SchemaNodeContainer) {
+ nodeDescriptions.addAll(getNodeDescriptions((SchemaNodeContainer) schemaNode));
+ } else {
+ YangNodeDescription nodeDescription = getNodeDescription(schemaNode);
+ if (nodeDescription != null) {
+ nodeDescriptions.add(nodeDescription);
+ }
+ }
+ }
+ return nodeDescriptions;
+ }
+
+ /**
+ * get yang statistics for yang schema context.
+ * @param schemaContext yang schema context.
+ * @return list of node description.
+ */
+ public List<YangNodeDescription> getYangStatistics(YangSchemaContext schemaContext) {
+ List<YangNodeDescription> nodeDescriptions = new ArrayList<>();
+ if (schemaContext == null) {
+ return nodeDescriptions;
+ }
+ for (Module module : schemaContext.getModules()) {
+ if (module instanceof SubModule) {
+ continue;
+ }
+ nodeDescriptions.addAll(getNodeDescriptions(module));
+ }
+ return nodeDescriptions;
+ }
+
+ /**
+ * serialize the yang statistics of schema context to xlsx format.
+ * @param schemaContext yang schema context.
+ * @return xlsx document
+ */
+ public SXSSFWorkbook serializeXlsx(YangSchemaContext schemaContext) {
+ SXSSFWorkbook workbook = new SXSSFWorkbook();
+ SXSSFSheet summary = workbook.createSheet("summary");
+ summary.setDisplayGridlines(true);
+ summary.setAutobreaks(true);
+ summary.setColumnWidth(0, 5000);
+ summary.setColumnWidth(1, 5000);
+ SXSSFRow sumFirstRow = summary.createRow(0);
+ SXSSFCell totalModules = sumFirstRow.createCell(0);
+ totalModules.setCellValue("Total modules:");
+ SXSSFCell totalModulesVal = sumFirstRow.createCell(1);
+ totalModulesVal.setCellValue(schemaContext.getModules().size());
+
+ SXSSFSheet detail = workbook.createSheet("detail");
+ detail.setDisplayGridlines(true);
+ detail.setAutobreaks(true);
+ detail.setColumnWidth(0, 20000);
+ detail.setColumnWidth(1, 5000);
+ detail.setColumnWidth(2, 20000);
+ detail.setColumnWidth(3, 5000);
+ detail.setColumnWidth(4, 5000);
+ detail.setColumnWidth(5, 5000);
+ detail.setColumnWidth(6, 5000);
+ detail.setColumnWidth(7, 5000);
+
+ CellStyle style = workbook.createCellStyle();
+ style.setBorderBottom(BorderStyle.THIN);
+ style.setBorderLeft(BorderStyle.THIN);
+ style.setBorderRight(BorderStyle.THIN);
+ style.setBorderTop(BorderStyle.THIN);
+
+ CellStyle desStyle = workbook.createCellStyle();
+ desStyle.cloneStyleFrom(style);
+ desStyle.setAlignment(HorizontalAlignment.JUSTIFY);
+
+ detail.setDefaultColumnStyle(0, style);
+ detail.setDefaultColumnStyle(1, desStyle);
+ detail.setDefaultColumnStyle(2, style);
+ detail.setDefaultColumnStyle(3, style);
+ detail.setDefaultColumnStyle(4, style);
+ detail.setDefaultColumnStyle(5, style);
+ detail.setDefaultColumnStyle(6, style);
+ detail.setDefaultColumnStyle(7, style);
+
+ //generate header
+ SXSSFRow firstRow = detail.createRow(0);
+ SXSSFCell yangpath = firstRow.createCell(0);
+ yangpath.setCellValue("Path");
+ yangpath.setCellStyle(style);
+ SXSSFCell active = firstRow.createCell(1);
+ active.setCellValue("Active");
+ active.setCellStyle(style);
+ SXSSFCell description = firstRow.createCell(2);
+ description.setCellValue("Description");
+ description.setCellStyle(style);
+ SXSSFCell config = firstRow.createCell(3);
+ config.setCellValue("Config");
+ config.setCellStyle(style);
+ SXSSFCell schema = firstRow.createCell(4);
+ schema.setCellValue("schema");
+ schema.setCellStyle(style);
+ SXSSFCell type = firstRow.createCell(5);
+ type.setCellValue("type");
+ type.setCellStyle(style);
+ SXSSFCell moduleHeader = firstRow.createCell(6);
+ moduleHeader.setCellValue("module");
+ moduleHeader.setCellStyle(style);
+ SXSSFCell deviated = firstRow.createCell(7);
+ deviated.setCellValue("deviated");
+ deviated.setCellStyle(style);
+
+
+ List<YangNodeDescription> totalPaths = getYangStatistics(schemaContext);
+
+
+ if (null != totalPaths) {
+ int pathSize = totalPaths.size();
+ SXSSFRow summarySecRow = summary.createRow(1);
+ SXSSFCell totalNodes = summarySecRow.createCell(0);
+ totalNodes.setCellValue("Total nodes:");
+ SXSSFCell totalNodesVal = summarySecRow.createCell(1);
+ totalNodesVal.setCellValue(pathSize);
+ for (int i = 0; i < pathSize; i++) {
+ YangNodeDescription path = totalPaths.get(i);
+ SXSSFRow row = detail.createRow(i + 1);
+ SXSSFCell pathCell = row.createCell(0);
+ pathCell.setCellValue(path.getPath());
+ pathCell.setCellStyle(style);
+ SXSSFCell activeCell = row.createCell(1);
+ activeCell.setCellValue(path.isActive());
+ activeCell.setCellStyle(style);
+ SXSSFCell descriptionCell = row.createCell(2);
+ String str = path.getDescription();
+ if (str.length() >= 32767) {
+ str = str.substring(0, 32767);
+ }
+ descriptionCell.setCellValue(str);
+ descriptionCell.setCellStyle(desStyle);
+
+ SXSSFCell configCell = row.createCell(3);
+ configCell.setCellValue(path.getConfig());
+ configCell.setCellStyle(style);
+
+ SXSSFCell schemaCell = row.createCell(4);
+ schemaCell.setCellValue(path.getSchemaType());
+ schemaCell.setCellStyle(style);
+
+ SXSSFCell typeCell = row.createCell(5);
+ typeCell.setCellValue(path.getNodeType());
+ typeCell.setCellStyle(style);
+
+ SXSSFCell moduleCell = row.createCell(6);
+ moduleCell.setCellValue(path.getModule());
+ moduleCell.setCellStyle(style);
+ SXSSFCell deviateCell = row.createCell(7);
+ deviateCell.setCellValue(path.isDeviated());
+ deviateCell.setCellStyle(style);
+ }
+ }
+ return workbook;
+ }
+
+ /**
+ * a yang compiler plugin implementation (run method).
+ * @param schemaContext yang schema context
+ * @param yangCompiler yang compiler instance
+ * @param parameters parameters for plugin
+ * @throws YangCompilerException if error occurs, throw the exception
+ */
+ @Override
+ public void run(YangSchemaContext schemaContext, YangCompiler yangCompiler,
+ List<YangCompilerPluginParameter> parameters) throws YangCompilerException {
+
+ YangCompilerPluginParameter para = parameters.get(0);
+ if (!para.getName().equals("output")) {
+ throw new YangCompilerException("unknown parameter:" + para.getName());
+ }
+ String output = (String) para.getValue();
+ SXSSFWorkbook workbook = serializeXlsx(schemaContext);
+ try {
+ workbook.write(new FileOutputStream(output));
+ workbook.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/validator/YangValidator.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/validator/YangValidator.java
new file mode 100644
index 0000000..5131416
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/validator/YangValidator.java
@@ -0,0 +1,46 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.validator;
+
+import java.util.List;
+
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+import org.onap.modeling.yangkit.plugin.YangCompilerPluginParameter;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+import org.yangcentral.yangkit.utils.file.FileUtil;
+
+
+public class YangValidator implements YangCompilerPlugin {
+ /**
+ * the implementation of run method.
+ * @param schemaContext yang schema context.
+ * @param yangCompiler yang compiler instance.
+ * @param parameters parameters of plugin.
+ * @throws YangCompilerException if error occurs, the exception will be thrown.
+ */
+ @Override
+ public void run(YangSchemaContext schemaContext, YangCompiler yangCompiler,
+ List<YangCompilerPluginParameter> parameters) throws YangCompilerException {
+ YangCompilerPluginParameter parameter = parameters.get(0);
+ if (!parameter.getName().equals("output")) {
+ throw new YangCompilerException("unknown parameter:" + parameter.getName());
+ }
+ FileUtil.writeUtf8File((String) parameter.getValue(), schemaContext.getValidateResult().toString());
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/ModuleInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/ModuleInfo.java
new file mode 100644
index 0000000..1b2a4b4
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/ModuleInfo.java
@@ -0,0 +1,117 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+public class ModuleInfo extends SubComponentInfo {
+ private URI namespace;
+ private final List<SubModuleInfo> subModules = new ArrayList<>();
+
+ /**
+ * constructor.
+ * @param name module name
+ * @param revision module revision
+ */
+ public ModuleInfo(String name, String revision) {
+ super(name, revision);
+ }
+
+ /**
+ * constructor.
+ * @param name module name
+ */
+ public ModuleInfo(String name) {
+ super(name);
+ }
+
+ /**
+ * serialize the revision.
+ * @return serialized revision
+ */
+ @Override
+ protected Map.Entry<String, String> serializeRevision() {
+ if (this.getRevision() == null) {
+ return null;
+ }
+ return new AbstractMap.SimpleEntry<>("revision", this.getRevision());
+ }
+
+ /**
+ * get namespace.
+ * @return the uri of namespace
+ */
+ public URI getNamespace() {
+ return namespace;
+ }
+
+ /**
+ * set namespace.
+ * @param namespace the uri of namespace
+ */
+ public void setNamespace(URI namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * get submodules.
+ * @return list of submodules.
+ */
+ public List<SubModuleInfo> getSubModules() {
+ return subModules;
+ }
+
+ /**
+ * add submodule.
+ * @param subModuleInfo submodule
+ */
+ public void addSubModule(SubModuleInfo subModuleInfo) {
+ if (subModules.contains(subModuleInfo)) {
+ return;
+ }
+ subModules.add(subModuleInfo);
+ }
+
+ /**
+ * serialize the module information.
+ * @return json element.
+ */
+ @Override
+ public JsonElement serialize() {
+ JsonObject jsonObject = super.serialize().getAsJsonObject();
+ if (this.getNamespace() != null) {
+ jsonObject.addProperty("namespace", this.getNamespace().toString());
+ }
+ if (!this.getSubModules().isEmpty()) {
+ JsonArray subModules = new JsonArray();
+ for (SubModuleInfo subModule : this.getSubModules()) {
+ subModules.add(subModule.serialize());
+ }
+ jsonObject.add("submodule", subModules);
+ }
+ return jsonObject;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/PackageInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/PackageInfo.java
new file mode 100644
index 0000000..a46f5f3
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/PackageInfo.java
@@ -0,0 +1,45 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import java.util.AbstractMap;
+import java.util.Map;
+
+
+public class PackageInfo extends SubComponentInfo {
+ /**
+ * constructor.
+ * @param name package name
+ * @param revision package revision.
+ */
+ public PackageInfo(String name, String revision) {
+ super(name, revision);
+ }
+
+ /**
+ * serialize the revision.
+ * @return serialized revision.
+ */
+ @Override
+ protected Map.Entry<String, String> serializeRevision() {
+ if (this.getRevision() == null) {
+ return null;
+ }
+ Map.Entry<String, String> revisionEntry = new AbstractMap.SimpleEntry<>("version", this.getRevision());
+ return revisionEntry;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubComponentInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubComponentInfo.java
new file mode 100644
index 0000000..6cdd005
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubComponentInfo.java
@@ -0,0 +1,171 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+
+public abstract class SubComponentInfo {
+ private final String name;
+ private String revision;
+ private final List<String> replaceRevisions = new ArrayList<>();
+ private List<URI> locations;
+
+ /**
+ * constructor.
+ * @param name the name of subcomponent.
+ * @param revision the revision of subcomponent.
+ */
+ public SubComponentInfo(String name, String revision) {
+ this.name = name;
+ this.revision = revision;
+ }
+
+ /**
+ * constructor.
+ * @param name the name of subcomponent.
+ */
+ public SubComponentInfo(String name) {
+ this.name = name;
+ }
+
+ /**
+ * get the name of subcomponent.
+ * @return name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the revision of subcomponent.
+ * @return revision
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * set the revision of subcomponent.
+ * @param revision revision
+ */
+ public void setRevision(String revision) {
+ this.revision = revision;
+ }
+
+ /**
+ * get the replaced revisions.
+ * @return the list of revisions.
+ */
+ public List<String> getReplaceRevisions() {
+ return replaceRevisions;
+ }
+
+ /**
+ * add replace revision.
+ * @param revision the revision to be replaced.
+ */
+ public void addReplaceRevision(String revision) {
+ if (replaceRevisions.contains(revision)) {
+ return;
+ }
+ replaceRevisions.add(revision);
+ }
+
+ /**
+ * get locations of subcomponent.
+ * @return list of location uri.
+ */
+ public List<URI> getLocations() {
+ return locations;
+ }
+
+ /**
+ * add location.
+ * @param location location uri.
+ */
+ public void addLocation(URI location) {
+ if (locations.contains(location)) {
+ return;
+ }
+ locations.add(location);
+ }
+
+ /**
+ * equals method.
+ * @param obj other object.
+ * @return true or false.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SubComponentInfo)) {
+ return false;
+ }
+ SubComponentInfo that = (SubComponentInfo) obj;
+ return getName().equals(that.getName()) && getRevision().equals(that.getRevision());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getName(), getRevision());
+ }
+
+ /**
+ * the abstract method of serialize the revision.
+ * @return serialized revision.
+ */
+ protected abstract Map.Entry<String, String> serializeRevision();
+
+ /**
+ * serialize the subcomponent to json element.
+ * @return json element.
+ */
+ public JsonElement serialize() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("name", this.getName());
+ if (this.getRevision() != null) {
+ Map.Entry<String, String> revisionEntry = serializeRevision();
+ jsonObject.addProperty(revisionEntry.getKey(), revisionEntry.getValue());
+ }
+ if (!this.getReplaceRevisions().isEmpty()) {
+ JsonArray replaceRevisions = new JsonArray();
+ for (String replaceRevision : this.getReplaceRevisions()) {
+ replaceRevisions.add(replaceRevision);
+ }
+ jsonObject.add("replaces-version", replaceRevisions);
+ }
+ if (!this.getLocations().isEmpty()) {
+ JsonArray locations = new JsonArray();
+ for (URI location : this.getLocations()) {
+ locations.add(location.toString());
+ }
+ jsonObject.add("location", locations);
+ }
+ return jsonObject;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubModuleInfo.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubModuleInfo.java
new file mode 100644
index 0000000..eb290fc
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/SubModuleInfo.java
@@ -0,0 +1,125 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+public class SubModuleInfo {
+ private final String name;
+ private final String revision;
+ private List<URI> locations = new ArrayList<>();
+
+ /**
+ * constructor.
+ * @param name submodule name
+ * @param revision submodule revision
+ */
+ public SubModuleInfo(String name, String revision) {
+ this.name = name;
+ this.revision = revision;
+ }
+
+ /**
+ * get the submodule name.
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the revision of submodule.
+ * @return revision
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * get locations of submodule.
+ * @return list of location.
+ */
+ public List<URI> getLocations() {
+ return locations;
+ }
+
+ /**
+ * set the locations.
+ * @param locations list of location.
+ */
+ public void setLocations(List<URI> locations) {
+ this.locations = locations;
+ }
+
+ /**
+ * add a location.
+ * @param location location uri
+ */
+ public void addLocation(URI location) {
+ if (locations.contains(location)) {
+ return;
+ }
+ locations.add(location);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SubModuleInfo)) {
+ return false;
+ }
+ SubModuleInfo that = (SubModuleInfo) obj;
+ return getName().equals(that.getName()) && getRevision().equals(that.getRevision());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getName(), getRevision());
+ }
+
+ /**
+ * serialize submodule to json.
+ * @return json element.
+ */
+ public JsonElement serialize() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("name", this.getName());
+ if (this.getRevision() != null) {
+ jsonObject.addProperty("revision", this.getRevision());
+ }
+
+ if (!this.getLocations().isEmpty()) {
+ JsonArray locations = new JsonArray();
+ for (URI location : this.getLocations()) {
+ locations.add(location.toString());
+ }
+ jsonObject.add("location", locations);
+ }
+ return jsonObject;
+
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackage.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackage.java
new file mode 100644
index 0000000..2a7913f
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackage.java
@@ -0,0 +1,395 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class YangPackage {
+ private final String name;
+ private final String revision;
+ private String timestamp;
+ private String organization;
+ private String contact;
+ private String description;
+ private String reference;
+ private boolean complete = true;
+ private boolean local;
+ private List<String> tags = new ArrayList<>();
+ private List<String> mandatoryFeatures = new ArrayList<>();
+ private List<PackageInfo> includePackages = new ArrayList<>();
+ private List<ModuleInfo> modules = new ArrayList<>();
+ private List<ModuleInfo> importOnlyModules = new ArrayList<>();
+
+ /**
+ * constructor.
+ * @param name package name
+ * @param revision package revision
+ */
+ public YangPackage(String name, String revision) {
+ this.name = name;
+ this.revision = revision;
+ }
+
+ /**
+ * get the package name.
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get the package revision.
+ * @return revision
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * get the timestamp.
+ * @return timestamp.
+ */
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * set the timestamp.
+ * @param timestamp timestamp
+ */
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ /**
+ * get organization.
+ * @return organization.
+ */
+ public String getOrganization() {
+ return organization;
+ }
+
+ /**
+ * set organization.
+ * @param organization organization
+ */
+ public void setOrganization(String organization) {
+ this.organization = organization;
+ }
+
+ /**
+ * get contact information.
+ * @return contact.
+ */
+ public String getContact() {
+ return contact;
+ }
+
+ /**
+ * set the contact.
+ * @param contact contact.
+ */
+ public void setContact(String contact) {
+ this.contact = contact;
+ }
+
+ /**
+ * get description.
+ * @return description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * set description.
+ * @param description description.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * get reference.
+ * @return reference.
+ */
+ public String getReference() {
+ return reference;
+ }
+
+ /**
+ * set reference.
+ * @param reference reference.
+ */
+ public void setReference(String reference) {
+ this.reference = reference;
+ }
+
+ /**
+ * whether the package is complete.
+ * @return true or false.
+ */
+ public boolean isComplete() {
+ return complete;
+ }
+
+ /**
+ * set whether the package is complete.
+ * @param complete true or false.
+ */
+ public void setComplete(boolean complete) {
+ this.complete = complete;
+ }
+
+ /**
+ * whether the package is local.
+ * @return true or false
+ */
+ public boolean isLocal() {
+ return local;
+ }
+
+ /**
+ * set whether the package is local.
+ * @param local true or false
+ */
+ public void setLocal(boolean local) {
+ this.local = local;
+ }
+
+ /**
+ * get the tags of package.
+ * @return the list of tags.
+ */
+ public List<String> getTags() {
+ return tags;
+ }
+
+ /**
+ * set the tags of package.
+ * @param tags the list of tags.
+ */
+ public void setTags(List<String> tags) {
+ this.tags = tags;
+ }
+
+ /**
+ * add a tag to package.
+ * @param tag tag
+ */
+ public void addTag(String tag) {
+ if (tags.contains(tag)) {
+ return;
+ }
+ tags.add(tag);
+ }
+
+ /**
+ * get mandatory features of package.
+ * @return list of features.
+ */
+ public List<String> getMandatoryFeatures() {
+ return mandatoryFeatures;
+ }
+
+ /**
+ * set mandatory features.
+ * @param mandatoryFeatures list of mandatory features.
+ */
+ public void setMandatoryFeatures(List<String> mandatoryFeatures) {
+ this.mandatoryFeatures = mandatoryFeatures;
+ }
+
+ /**
+ * add mandatory feature.
+ * @param feature feature
+ */
+ public void addMandatoryFeature(String feature) {
+ if (mandatoryFeatures.contains(feature)) {
+ return;
+ }
+ mandatoryFeatures.add(feature);
+ }
+
+ /**
+ * get include packages.
+ * @return list of included packages.
+ */
+ public List<PackageInfo> getIncludePackages() {
+ return includePackages;
+ }
+
+ /**
+ * set the include packages.
+ * @param includePackages the list of include packages.
+ */
+ public void setIncludePackages(List<PackageInfo> includePackages) {
+ this.includePackages = includePackages;
+ }
+
+ /**
+ * add a include package.
+ * @param packageInfo package
+ */
+ public void addIncludePackage(PackageInfo packageInfo) {
+ if (includePackages.contains(packageInfo)) {
+ return;
+ }
+ includePackages.add(packageInfo);
+ }
+
+ /**
+ * get the modules of package.
+ * @return list of modules.
+ */
+ public List<ModuleInfo> getModules() {
+ return modules;
+ }
+
+ /**
+ * set the modules of package.
+ * @param modules list of modules
+ */
+ public void setModules(List<ModuleInfo> modules) {
+ this.modules = modules;
+ }
+
+ /**
+ * add a module to package.
+ * @param module module
+ */
+ public void addModule(ModuleInfo module) {
+ if (this.modules.contains(module)) {
+ return;
+ }
+ modules.add(module);
+ }
+
+ /**
+ * get import-only modules.
+ * @return list of modules.
+ */
+ public List<ModuleInfo> getImportOnlyModules() {
+ return importOnlyModules;
+ }
+
+ /**
+ * add a import-only module.
+ * @param module module
+ */
+ public void addImportOnlyModule(ModuleInfo module) {
+ if (importOnlyModules.contains(module)) {
+ return;
+ }
+ importOnlyModules.add(module);
+ }
+
+ /**
+ * set import-only modules.
+ * @param importOnlyModules list of modules
+ */
+ public void setImportOnlyModules(List<ModuleInfo> importOnlyModules) {
+ this.importOnlyModules = importOnlyModules;
+ }
+
+ /**
+ * serialize yang package to json.
+ * @return json element
+ */
+ public JsonElement serialize() {
+ JsonObject document = new JsonObject();
+ JsonObject instanceDataset = new JsonObject();
+ document.add("ietf-yang-instance-data:instance-data-set", instanceDataset);
+ instanceDataset.addProperty("name", this.getName());
+ JsonObject contentSchema = new JsonObject();
+ instanceDataset.add("content-schema", contentSchema);
+ JsonArray moduleArray = new JsonArray();
+ moduleArray.add("ietf-yang-package-instance@2020-01-21");
+ contentSchema.add("module", moduleArray);
+ JsonObject contentData = new JsonObject();
+ instanceDataset.add("content-data", contentData);
+ JsonObject yangPackage = new JsonObject();
+ contentData.add("ietf-yang-package-instance:yang-package", yangPackage);
+ yangPackage.addProperty("name", this.getName());
+ yangPackage.addProperty("version", this.getRevision());
+ // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+ // String dateTime = sdf.format(new Date(System.currentTimeMillis()));
+ if (this.getTimestamp() != null) {
+ yangPackage.addProperty("timestamp", this.getTimestamp());
+ }
+
+ if (this.getOrganization() != null) {
+ yangPackage.addProperty("organization", this.getOrganization());
+ }
+ if (this.getContact() != null) {
+ yangPackage.addProperty("contact", this.getContact());
+ }
+ if (this.getDescription() != null) {
+ yangPackage.addProperty("description", this.getDescription());
+ }
+ if (this.getReference() != null) {
+ yangPackage.addProperty("reference", this.getReference());
+ }
+ yangPackage.addProperty("complete", this.isComplete());
+ yangPackage.addProperty("local", this.isLocal());
+
+ if (!this.getTags().isEmpty()) {
+ JsonArray tags = new JsonArray();
+ for (String tag : this.getTags()) {
+ tags.add(tag);
+ }
+ yangPackage.add("tag", tags);
+ }
+ if (!this.getMandatoryFeatures().isEmpty()) {
+ JsonArray mandatoryFeatures = new JsonArray();
+ for (String mandatoryFeature : this.getMandatoryFeatures()) {
+ mandatoryFeatures.add(mandatoryFeature);
+ }
+ yangPackage.add("mandatory-feature", mandatoryFeatures);
+ }
+ if (!this.getIncludePackages().isEmpty()) {
+ JsonArray includePackages = new JsonArray();
+ for (PackageInfo packageInfo : this.getIncludePackages()) {
+ includePackages.add(packageInfo.serialize());
+ }
+ yangPackage.add("included-package", includePackages);
+ }
+ if (!this.getModules().isEmpty()) {
+ JsonArray modules = new JsonArray();
+ for (ModuleInfo moduleInfo : this.getModules()) {
+ modules.add(moduleInfo.serialize());
+ }
+ yangPackage.add("module", modules);
+ }
+
+ if (!this.getImportOnlyModules().isEmpty()) {
+ JsonArray importOnlyModules = new JsonArray();
+ for (ModuleInfo importOnlyModule : this.getImportOnlyModules()) {
+ importOnlyModules.add(importOnlyModule.serialize());
+ }
+ yangPackage.add("import-only-module", importOnlyModules);
+ }
+ return yangPackage;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageGenerator.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageGenerator.java
new file mode 100644
index 0000000..a6cfbef
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageGenerator.java
@@ -0,0 +1,154 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.util.List;
+import java.util.Properties;
+
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+import org.onap.modeling.yangkit.plugin.YangCompilerPluginParameter;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+import org.yangcentral.yangkit.model.api.stmt.Include;
+import org.yangcentral.yangkit.model.api.stmt.MainModule;
+import org.yangcentral.yangkit.model.api.stmt.Module;
+import org.yangcentral.yangkit.model.api.stmt.SubModule;
+
+
+public class YangPackageGenerator implements YangCompilerPlugin {
+ @Override
+ public YangCompilerPluginParameter getParameter(Properties compilerProps, String name, String value)
+ throws YangCompilerException {
+ if (!name.equals("complete") && !name.equals("meta") && !name.equals("output")) {
+ throw new YangCompilerException("unrecognized parameter:" + name);
+ }
+ if (name.equals("complete")) {
+ YangCompilerPluginParameter pluginParameter = new YangCompilerPluginParameter() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Object getValue() throws YangCompilerException {
+ return Boolean.valueOf(value);
+ }
+ };
+ return pluginParameter;
+ }
+ return YangCompilerPlugin.super.getParameter(compilerProps, name, value);
+ }
+
+ @Override
+ public void run(YangSchemaContext schemaContext, YangCompiler yangCompiler,
+ List<YangCompilerPluginParameter> parameters)
+ throws YangCompilerException {
+ String output = null;
+ for (YangCompilerPluginParameter parameter : parameters) {
+ if (parameter.getName().equals("output")) {
+ output = (String) parameter.getValue();
+ } else {
+ throw new YangCompilerException("unknown parameter:" + parameter.getName());
+ }
+ }
+ if (output == null) {
+ throw new YangCompilerException("missing mandatory parameter:output");
+ }
+
+ File yangDir = yangCompiler.getYang();
+ //search package_meta.json
+ File packageMetaFile = new File(yangDir, "package_meta.json");
+ if (!packageMetaFile.exists()) {
+ throw new YangCompilerException("missing package_meta.json in directory:" + yangDir.getAbsolutePath());
+ }
+
+ try {
+ //parse yang package meta information
+ JsonElement element = JsonParser.parseReader(new FileReader(packageMetaFile));
+ YangPackageMeta yangPackageMeta = new YangPackageMeta();
+ yangPackageMeta.deserialize(element);
+ //set meta information for yang package
+ YangPackage yangPackage = new YangPackage(yangPackageMeta.getName(), yangPackageMeta.getRevision());
+ yangPackage.setOrganization(yangPackageMeta.getOrganization());
+ yangPackage.setContact(yangPackageMeta.getContact());
+ yangPackage.setDescription(yangPackageMeta.getDescription());
+ yangPackage.setReference(yangPackageMeta.getReference());
+ yangPackage.setLocal(yangPackageMeta.isLocal());
+ yangPackage.setTags(yangPackageMeta.getTags());
+ yangPackage.setMandatoryFeatures(yangPackageMeta.getMandatoryFeatures());
+ yangPackage.setIncludePackages(yangPackageMeta.getIncludePackages());
+ if (schemaContext.getImportOnlyModules().isEmpty()) {
+ yangPackage.setComplete(true);
+ }
+ FilenameFilter packageMetaFilter = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ if (name.equals("package_meta.json")) {
+ return true;
+ }
+ return false;
+ }
+ };
+ File[] metaFiles = yangDir.listFiles(packageMetaFilter);
+ List<Module> modules = schemaContext.getModules();
+ for (Module module : modules) {
+ if (module instanceof MainModule) {
+ ModuleInfo moduleInfo = new ModuleInfo(module.getArgStr(), module.getCurRevisionDate().get());
+ moduleInfo.setNamespace(((MainModule) module).getNamespace().getUri());
+ if (!module.getIncludes().isEmpty()) {
+ for (Include include : module.getIncludes()) {
+ SubModule subModule = include.getInclude().get();
+ SubModuleInfo subModuleInfo =
+ new SubModuleInfo(subModule.getArgStr(), subModule.getCurRevisionDate().get());
+ moduleInfo.addSubModule(subModuleInfo);
+ }
+ }
+ yangPackage.addModule(moduleInfo);
+ }
+ }
+ for (Module importOnlyModule : schemaContext.getImportOnlyModules()) {
+ if (!(importOnlyModule instanceof MainModule)) {
+ continue;
+ }
+ ModuleInfo moduleInfo =
+ new ModuleInfo(importOnlyModule.getArgStr(), importOnlyModule.getCurRevisionDate().get());
+ moduleInfo.setNamespace(((MainModule) importOnlyModule).getNamespace().getUri());
+ if (!importOnlyModule.getIncludes().isEmpty()) {
+ for (Include include : importOnlyModule.getIncludes()) {
+ SubModule subModule = include.getInclude().get();
+ SubModuleInfo subModuleInfo =
+ new SubModuleInfo(subModule.getArgStr(), subModule.getCurRevisionDate().get());
+ moduleInfo.addSubModule(subModuleInfo);
+ }
+ }
+ yangPackage.addImportOnlyModule(moduleInfo);
+ }
+
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageMeta.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageMeta.java
new file mode 100644
index 0000000..40da4ba
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangpackage/YangPackageMeta.java
@@ -0,0 +1,187 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangpackage;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class YangPackageMeta {
+ private String name;
+ private String revision;
+ private String organization;
+ private String contact;
+ private String description;
+ private String reference;
+ private boolean local;
+ private final List<String> tags = new ArrayList<>();
+ private final List<String> mandatoryFeatures = new ArrayList<>();
+ private final List<PackageInfo> includePackages = new ArrayList<>();
+
+ /**
+ * get the package name.
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * get revision of package.
+ * @return revision
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+ /**
+ * get organization.
+ * @return organization.
+ */
+ public String getOrganization() {
+ return organization;
+ }
+
+ /**
+ * get contact.
+ * @return contact.
+ */
+ public String getContact() {
+ return contact;
+ }
+
+ /**
+ * get description.
+ * @return description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * get reference.
+ * @return reference.
+ */
+ public String getReference() {
+ return reference;
+ }
+
+ /**
+ * whether the package is local.
+ * @return true or false
+ */
+ public boolean isLocal() {
+ return local;
+ }
+
+ /**
+ * get tags of package.
+ * @return list of tags.
+ */
+ public List<String> getTags() {
+ return tags;
+ }
+
+ /**
+ * get mandatory features.
+ * @return list of features/
+ */
+ public List<String> getMandatoryFeatures() {
+ return mandatoryFeatures;
+ }
+
+ /**
+ * get include packages.
+ * @return list of packages.
+ */
+ public List<PackageInfo> getIncludePackages() {
+ return includePackages;
+ }
+
+ /**
+ * deserialized package meta from json.
+ * @param metaDoc json element
+ */
+ public void deserialize(JsonElement metaDoc) {
+ JsonObject jsonObject = metaDoc.getAsJsonObject();
+ JsonElement nameElement = jsonObject.get("name");
+ if (nameElement != null) {
+ this.name = nameElement.getAsString();
+ }
+ JsonElement versionElement = jsonObject.get("version");
+ if (versionElement != null) {
+ this.revision = versionElement.getAsString();
+ }
+ JsonElement organizationElement = jsonObject.get("organization");
+ if (organizationElement != null) {
+ this.organization = organizationElement.getAsString();
+ }
+ JsonElement contactElement = jsonObject.get("contact");
+ if (contactElement != null) {
+ this.contact = contactElement.getAsString();
+ }
+ JsonElement descElement = jsonObject.get("description");
+ if (descElement != null) {
+ this.description = descElement.getAsString();
+ }
+ JsonElement referElement = jsonObject.get("reference");
+ if (referElement != null) {
+ this.reference = referElement.getAsString();
+ }
+
+ JsonElement localElement = jsonObject.get("local");
+ if (localElement != null) {
+ this.local = referElement.getAsBoolean();
+ }
+ JsonElement tagElement = jsonObject.get("tag");
+ if (tagElement != null) {
+ JsonArray tagArray = tagElement.getAsJsonArray();
+ int size = tagArray.size();
+ for (int i = 0; i < size; i++) {
+ JsonElement tagIns = tagArray.get(i);
+ this.tags.add(tagIns.getAsString());
+ }
+ }
+
+ JsonElement mandatoryFeaturesElement = jsonObject.get("mandatory-feature");
+ if (mandatoryFeaturesElement != null) {
+ JsonArray mandatoryFeaturesArray = mandatoryFeaturesElement.getAsJsonArray();
+ int size = mandatoryFeaturesArray.size();
+ for (int i = 0; i < size; i++) {
+ JsonElement featureIns = mandatoryFeaturesArray.get(i);
+ this.mandatoryFeatures.add(featureIns.getAsString());
+ }
+ }
+ JsonElement includePackagesElement = jsonObject.get("include-package");
+ if (includePackagesElement != null) {
+ JsonArray includePackageArray = includePackagesElement.getAsJsonArray();
+ int size = includePackageArray.size();
+ for (int i = 0; i < size; i++) {
+ JsonElement includePackageIns = includePackageArray.get(i);
+ JsonObject includePackageObj = includePackageIns.getAsJsonObject();
+ PackageInfo packageInfo = new PackageInfo(includePackageObj.get("name").getAsString(),
+ includePackageObj.get("version").getAsString());
+ this.includePackages.add(packageInfo);
+ }
+ }
+
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/GroupingSchemaNodeContainer.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/GroupingSchemaNodeContainer.java
new file mode 100644
index 0000000..67fd48d
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/GroupingSchemaNodeContainer.java
@@ -0,0 +1,141 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangtree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.yangcentral.yangkit.common.api.QName;
+import org.yangcentral.yangkit.common.api.validate.ValidatorResult;
+import org.yangcentral.yangkit.model.api.stmt.Action;
+import org.yangcentral.yangkit.model.api.stmt.ActionContainer;
+import org.yangcentral.yangkit.model.api.stmt.Augment;
+import org.yangcentral.yangkit.model.api.stmt.DataDefContainer;
+import org.yangcentral.yangkit.model.api.stmt.DataDefinition;
+import org.yangcentral.yangkit.model.api.stmt.DataNode;
+import org.yangcentral.yangkit.model.api.stmt.Grouping;
+import org.yangcentral.yangkit.model.api.stmt.GroupingDefContainer;
+import org.yangcentral.yangkit.model.api.stmt.Notification;
+import org.yangcentral.yangkit.model.api.stmt.NotificationContainer;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNode;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNodeContainer;
+import org.yangcentral.yangkit.model.api.stmt.Uses;
+import org.yangcentral.yangkit.model.api.stmt.YangStatement;
+
+
+public class GroupingSchemaNodeContainer implements SchemaNodeContainer, GroupingDefContainer {
+
+ private final YangStatement container;
+
+ /**
+ * constructor.
+ * @param container schema node container
+ */
+ public GroupingSchemaNodeContainer(YangStatement container) {
+ this.container = container;
+ }
+
+ @Override
+ public List<Grouping> getGroupings() {
+ List<Grouping> groupings = new ArrayList<>();
+ if (container instanceof GroupingDefContainer) {
+ groupings.addAll(((GroupingDefContainer) container).getGroupings());
+ }
+ return groupings;
+ }
+
+ @Override
+ public Grouping getGrouping(String name) {
+ return null;
+ }
+
+ @Override
+ public List<SchemaNode> getSchemaNodeChildren() {
+ List<SchemaNode> schemaNodes = new ArrayList<>();
+ if (container instanceof DataDefContainer) {
+ DataDefContainer dataDefContainer = (DataDefContainer) container;
+ for (DataDefinition dataDefinition : dataDefContainer.getDataDefChildren()) {
+ schemaNodes.add(dataDefinition);
+ }
+ }
+
+ if (container instanceof ActionContainer) {
+ ActionContainer actionContainer = (ActionContainer) container;
+ for (Action action : actionContainer.getActions()) {
+ schemaNodes.add(action);
+ }
+ }
+
+ if (container instanceof NotificationContainer) {
+ for (Notification notification : ((NotificationContainer) container).getNotifications()) {
+ schemaNodes.add(notification);
+ }
+ }
+ if (container instanceof Uses) {
+ for (Augment augment : ((Uses) container).getAugments()) {
+ schemaNodes.add(augment);
+ }
+ }
+
+ return schemaNodes;
+ }
+
+ @Override
+ public ValidatorResult addSchemaNodeChild(SchemaNode schemaNode) {
+ return null;
+ }
+
+ @Override
+ public ValidatorResult addSchemaNodeChildren(List<SchemaNode> schemaNodes) {
+ return null;
+ }
+
+ @Override
+ public SchemaNode getSchemaNodeChild(QName identifier) {
+ return null;
+ }
+
+ @Override
+ public DataNode getDataNodeChild(QName identifier) {
+ return null;
+ }
+
+ @Override
+ public List<DataNode> getDataNodeChildren() {
+ return null;
+ }
+
+ @Override
+ public List<SchemaNode> getEffectiveSchemaNodeChildren(boolean ignoreNamespace) {
+ return null;
+ }
+
+ @Override
+ public void removeSchemaNodeChild(QName identifier) {
+
+ }
+
+ @Override
+ public void removeSchemaNodeChild(SchemaNode schemaNode) {
+
+ }
+
+ @Override
+ public SchemaNode getMandatoryDescendant() {
+ return null;
+ }
+}
diff --git a/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/YangTreeGenerator.java b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/YangTreeGenerator.java
new file mode 100644
index 0000000..45f7b94
--- /dev/null
+++ b/yang-compiler/src/main/java/org/onap/modeling/yangkit/plugin/yangtree/YangTreeGenerator.java
@@ -0,0 +1,654 @@
+/*
+Copyright 2023 Huawei Technologies
+
+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.
+*/
+
+package org.onap.modeling.yangkit.plugin.yangtree;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.onap.modeling.yangkit.compiler.YangCompiler;
+import org.onap.modeling.yangkit.compiler.YangCompilerException;
+import org.onap.modeling.yangkit.plugin.YangCompilerPlugin;
+import org.onap.modeling.yangkit.plugin.YangCompilerPluginParameter;
+import org.yangcentral.yangkit.common.api.QName;
+import org.yangcentral.yangkit.model.api.restriction.LeafRef;
+import org.yangcentral.yangkit.model.api.schema.SchemaTreeType;
+import org.yangcentral.yangkit.model.api.schema.YangSchemaContext;
+
+import org.yangcentral.yangkit.model.api.stmt.Action;
+import org.yangcentral.yangkit.model.api.stmt.Anydata;
+import org.yangcentral.yangkit.model.api.stmt.Anyxml;
+import org.yangcentral.yangkit.model.api.stmt.Augment;
+import org.yangcentral.yangkit.model.api.stmt.Case;
+import org.yangcentral.yangkit.model.api.stmt.Choice;
+import org.yangcentral.yangkit.model.api.stmt.Container;
+import org.yangcentral.yangkit.model.api.stmt.DataDefinition;
+import org.yangcentral.yangkit.model.api.stmt.Entity;
+import org.yangcentral.yangkit.model.api.stmt.Grouping;
+import org.yangcentral.yangkit.model.api.stmt.GroupingDefContainer;
+import org.yangcentral.yangkit.model.api.stmt.IfFeature;
+import org.yangcentral.yangkit.model.api.stmt.IfFeatureSupport;
+import org.yangcentral.yangkit.model.api.stmt.Leaf;
+import org.yangcentral.yangkit.model.api.stmt.MainModule;
+import org.yangcentral.yangkit.model.api.stmt.Module;
+import org.yangcentral.yangkit.model.api.stmt.MultiInstancesDataNode;
+import org.yangcentral.yangkit.model.api.stmt.Notification;
+import org.yangcentral.yangkit.model.api.stmt.Rpc;
+import org.yangcentral.yangkit.model.api.stmt.SchemaDataNode;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNode;
+import org.yangcentral.yangkit.model.api.stmt.SchemaNodeContainer;
+import org.yangcentral.yangkit.model.api.stmt.Status;
+import org.yangcentral.yangkit.model.api.stmt.TypedDataNode;
+import org.yangcentral.yangkit.model.api.stmt.Uses;
+import org.yangcentral.yangkit.model.api.stmt.YangList;
+import org.yangcentral.yangkit.model.api.stmt.YangStatement;
+import org.yangcentral.yangkit.model.api.stmt.YangUnknown;
+import org.yangcentral.yangkit.model.api.stmt.ext.AugmentStructure;
+import org.yangcentral.yangkit.model.api.stmt.ext.YangData;
+import org.yangcentral.yangkit.model.api.stmt.ext.YangDataStructure;
+import org.yangcentral.yangkit.utils.file.FileUtil;
+
+
+public class YangTreeGenerator implements YangCompilerPlugin {
+ private int lineLength = 72;
+ private boolean expandGrouping = true;
+ private String output;
+ private static final String SPACE = " ";
+ private static final String TWO_SPACES = " ";
+ private static final String OFFSET = " ";
+ private static final String VERTICAL_OFFSET = "| ";
+
+ /**
+ * build yang tree from module.
+ * @param module module
+ * @return yang tree string
+ */
+ public String buildYangTree(Module module) {
+ StringBuilder sb = new StringBuilder();
+ if (module instanceof MainModule) {
+ sb.append("module:");
+ } else {
+ sb.append("submodule:");
+ }
+ sb.append(SPACE);
+ sb.append(module.getArgStr());
+ sb.append("\n");
+ //data nodes
+ List<DataDefinition> dataDefs = module.getDataDefChildren();
+
+ //augments
+ List<Augment> augments = module.getAugments();
+
+
+ List<YangUnknown> yangDataList = module.getUnknowns(
+ new QName("urn:ietf:params:xml:ns:yang:ietf-restconf", "yang-data"));
+
+ // yang structure extension
+ List<YangUnknown> yangStructureList = module.getUnknowns(YangDataStructure.YANG_KEYWORD);
+
+ // augment structure extension
+ List<YangUnknown> augmentStructureList = module.getUnknowns(AugmentStructure.YANG_KEYWORD);
+
+ if (!module.getGroupings().isEmpty()
+ && (!expandGrouping
+ || (module.getDataDefChildren().isEmpty()
+ && module.getRpcs().isEmpty()
+ && module.getNotifications().isEmpty()
+ && module.getAugments().isEmpty()
+ && yangDataList.isEmpty()
+ && yangStructureList.isEmpty()
+ && augmentStructureList.isEmpty()))) {
+ sb.append(buildGroupingContainer(module, TWO_SPACES));
+ }
+ //data nodes
+ if (!dataDefs.isEmpty()) {
+ int size = dataDefs.size();
+ boolean last = false;
+ for (int i = 0; i < size; i++) {
+ if (i == (size - 1)) {
+ last = true;
+ }
+ DataDefinition dataDefinition = dataDefs.get(i);
+ sb.append(buildYangTree(dataDefinition, last, TWO_SPACES, !expandGrouping));
+ }
+ }
+ //augments
+ if (!augments.isEmpty()) {
+ for (Augment augment : augments) {
+ sb.append(buildAugmentRepresentation(augment, TWO_SPACES));
+ sb.append(buildChildren(augment, TWO_SPACES + TWO_SPACES, !expandGrouping));
+ }
+ }
+ //rpcs
+ List<Rpc> rpcs = module.getRpcs();
+ if (!rpcs.isEmpty()) {
+ sb.append(TWO_SPACES);
+ sb.append("rpcs:\n");
+ int size = rpcs.size();
+ boolean last = false;
+ for (int i = 0; i < size; i++) {
+ if (i == (size - 1)) {
+ last = true;
+ }
+ Rpc rpc = rpcs.get(i);
+ sb.append(buildYangTree(rpc, last, TWO_SPACES + TWO_SPACES, !expandGrouping));
+ }
+ }
+ //notifications
+ List<Notification> notifications = module.getNotifications();
+ if (!notifications.isEmpty()) {
+ sb.append(TWO_SPACES);
+ sb.append("notifications:\n");
+ int size = notifications.size();
+ boolean last = false;
+ for (int i = 0; i < size; i++) {
+ if (i == (size - 1)) {
+ last = true;
+ }
+ Notification notification = notifications.get(i);
+ sb.append(buildYangTree(notification, last, TWO_SPACES + TWO_SPACES, !expandGrouping));
+ }
+ }
+ //yang data
+ if (!yangDataList.isEmpty()) {
+ for (YangUnknown unknown : yangDataList) {
+ YangData yangData = (YangData) unknown;
+ sb.append(TWO_SPACES);
+ sb.append("yang-data");
+ sb.append(" ");
+ sb.append(yangData.getArgStr());
+ sb.append(":\n");
+ sb.append(buildChildren(yangData, TWO_SPACES + TWO_SPACES, !expandGrouping));
+ }
+ }
+ //structures
+ if (!yangStructureList.isEmpty()) {
+ for (YangUnknown unknown : yangStructureList) {
+ YangDataStructure structure = (YangDataStructure) unknown;
+ sb.append(TWO_SPACES);
+ sb.append("structure");
+ sb.append(" ");
+ sb.append(structure.getArgStr());
+ sb.append(":\n");
+ if (!expandGrouping) {
+ sb.append(buildGroupingContainer(structure, TWO_SPACES + TWO_SPACES));
+ }
+ sb.append(buildChildren(structure, TWO_SPACES + TWO_SPACES, !expandGrouping));
+
+ }
+ }
+ //augment-structures
+ if (!augmentStructureList.isEmpty()) {
+ for (YangUnknown unknown : augmentStructureList) {
+ AugmentStructure augmentStructure = (AugmentStructure) unknown;
+ sb.append(TWO_SPACES);
+ sb.append("augment-structure");
+ sb.append(" ");
+ sb.append(augmentStructure.getArgStr());
+ sb.append(":\n");
+ sb.append(buildChildren(augmentStructure, TWO_SPACES + TWO_SPACES, !expandGrouping));
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String buildYangTree(SchemaNode schemaNode, boolean last, String offSet, boolean grouping) {
+ StringBuilder sb = new StringBuilder();
+ if (!grouping && (schemaNode instanceof Uses)) {
+ Uses uses = (Uses) schemaNode;
+ List<SchemaNode> schemaNodes = uses.getSchemaNodeChildren();
+ for (int i = 0; i < schemaNodes.size(); i++) {
+ SchemaNode exSchemaNode = schemaNodes.get(i);
+ boolean subLast = last;
+ if (i != (schemaNodes.size() - 1)) {
+ subLast = false;
+ }
+ sb.append(buildYangTree(exSchemaNode, subLast, offSet, grouping));
+ }
+ return sb.toString();
+ }
+ if (schemaNode instanceof Augment) {
+ sb.append(buildAugmentRepresentation((Augment) schemaNode, offSet));
+ } else {
+ sb.append(buildNodeRepresentation(schemaNode, offSet));
+ }
+ if ((schemaNode instanceof GroupingDefContainer) && grouping) {
+ sb.append(buildGroupingContainer((GroupingDefContainer) schemaNode, offSet + TWO_SPACES));
+ }
+ if (schemaNode instanceof SchemaNodeContainer) {
+ String childOffSet = offSet;
+ if (schemaNode instanceof Augment) {
+ childOffSet = childOffSet.concat(TWO_SPACES);
+ } else {
+ if (last) {
+ childOffSet = childOffSet.concat(OFFSET);
+ } else {
+ childOffSet = childOffSet.concat(VERTICAL_OFFSET);
+ }
+ }
+
+ SchemaNodeContainer schemaNodeContainer;
+ if (!grouping) {
+ schemaNodeContainer = (SchemaNodeContainer) schemaNode;
+ } else {
+ schemaNodeContainer = new GroupingSchemaNodeContainer(schemaNode);
+ }
+
+ sb.append(buildChildren(schemaNodeContainer, childOffSet, grouping));
+ }
+
+ return sb.toString();
+ }
+
+ private String buildGroupingContainer(GroupingDefContainer groupingDefContainer, String offSet) {
+ StringBuilder sb = new StringBuilder();
+ //sb.append(offSet);
+ List<Grouping> groupings = groupingDefContainer.getGroupings();
+ int size = groupings.size();
+ for (int i = 0; i < size; i++) {
+ boolean last = false;
+ if (i == (size - 1)) {
+ last = true;
+ }
+ Grouping grouping = groupings.get(i);
+ sb.append(buildGrouping(grouping, last, offSet));
+ }
+ return sb.toString();
+ }
+
+ private List<SchemaNode> getRealSchemaChildren(SchemaNodeContainer schemaNodeContainer, boolean grouping) {
+ List<SchemaNode> realSchemaNodeChildren = new ArrayList<>();
+
+ for (SchemaNode schemaChild : schemaNodeContainer.getSchemaNodeChildren()) {
+ if (schemaChild instanceof Augment) {
+ Augment augment = (Augment) schemaChild;
+ if (schemaNodeContainer instanceof SchemaNode) {
+ SchemaNode schemaNodeParent = (SchemaNode) schemaNodeContainer;
+ if (augment.getContext().getNamespace() != null && !augment.getContext().getNamespace()
+ .equals(schemaNodeParent.getContext().getNamespace())) {
+ continue;
+ }
+ }
+ if (!grouping) {
+ realSchemaNodeChildren.addAll(getRealSchemaChildren(augment, grouping));
+ continue;
+ }
+ }
+ realSchemaNodeChildren.add(schemaChild);
+ }
+ return realSchemaNodeChildren;
+ }
+
+ private String buildChildren(SchemaNodeContainer schemaNodeContainer, String offSet, boolean grouping) {
+ StringBuilder sb = new StringBuilder();
+ List<SchemaNode> schemaNodeChildren = schemaNodeContainer.getSchemaNodeChildren();
+ List<SchemaNode> realSchemaNodeChildren = getRealSchemaChildren(schemaNodeContainer, grouping);
+
+ int size = realSchemaNodeChildren.size();
+ for (int i = 0; i < size; i++) {
+ SchemaNode realSchemaNode = realSchemaNodeChildren.get(i);
+ boolean subLast = false;
+ if (i == (size - 1)) {
+ subLast = true;
+ }
+ sb.append(buildYangTree(realSchemaNode, subLast, offSet, grouping));
+
+ }
+ return sb.toString();
+ }
+
+ private String buildGrouping(Grouping grouping, boolean last, String offset) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(offset);
+ sb.append("grouping ");
+ sb.append(grouping.getArgStr());
+ sb.append(":\n");
+ GroupingSchemaNodeContainer groupingSchemaNodeContainer = new GroupingSchemaNodeContainer(grouping);
+ sb.append(buildGroupingContainer(grouping, offset + TWO_SPACES));
+ sb.append(buildChildren(groupingSchemaNodeContainer, offset + TWO_SPACES, true));
+ return sb.toString();
+ }
+
+
+
+ private String getStatus(YangStatement yangStatement) {
+ if (yangStatement instanceof Entity) {
+ Status status = ((Entity) yangStatement).getEffectiveStatus();
+ switch (status) {
+ case CURRENT: {
+ return "+";
+ }
+ case DEPRECATED: {
+ return "x";
+ }
+ case OBSOLETE: {
+ return "o";
+ }
+ default:
+ throw new IllegalStateException("Unexpected value: " + status);
+ }
+ }
+ return "";
+ }
+
+ private String getFlags(YangStatement yangStatement) {
+ String flags = "";
+ if (yangStatement instanceof SchemaNode) {
+ SchemaNode schemaNode = (SchemaNode) yangStatement;
+ if (schemaNode instanceof Uses) {
+ flags = "-u";
+ } else if ((schemaNode instanceof Rpc) || (schemaNode instanceof Action)) {
+ flags = "-x";
+ } else if (schemaNode instanceof Notification) {
+ flags = "-n";
+ } else if (schemaNode instanceof Case) {
+ flags = "";
+ } else if (schemaNode.isConfig()) {
+ flags = "rw";
+ } else {
+ flags = "ro";
+ if (schemaNode.getSchemaTreeType() == SchemaTreeType.INPUTTREE) {
+ flags = "-w";
+ }
+ }
+
+ if (!schemaNode.getSubStatement(new QName("urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount",
+ "mount-point")).isEmpty()) {
+ flags = "mp";
+ }
+ } else if (yangStatement instanceof Grouping) {
+ flags = "rw";
+ }
+
+ return flags;
+ }
+
+ private String getNodeName(YangStatement yangStatement) {
+ if (yangStatement instanceof Case) {
+ return ":(" + yangStatement.getArgStr() + ")";
+ } else if (yangStatement instanceof Choice) {
+ return " (" + yangStatement.getArgStr() + ")";
+ } else {
+ return " " + yangStatement.getArgStr();
+ }
+ }
+
+ private boolean isMandatory(SchemaDataNode dataNode) {
+ //key nodes
+ if (dataNode instanceof Leaf) {
+ SchemaNodeContainer parent = dataNode.getClosestAncestorNode();
+ if (parent instanceof YangList) {
+ YangList list = (YangList) parent;
+ if (list.getKey().getKeyNode(dataNode.getIdentifier()) != null) {
+ return true;
+ }
+ }
+ }
+ return dataNode.isMandatory();
+ }
+
+ private String getOpts(YangStatement yangStatement) {
+ if ((yangStatement instanceof Leaf)
+ || (yangStatement instanceof Choice)
+ || (yangStatement instanceof Anydata)
+ || (yangStatement instanceof Anyxml)) {
+ if (!isMandatory((SchemaDataNode) yangStatement)) {
+ return "?";
+ }
+ } else if (yangStatement instanceof Container) {
+ if (((Container) yangStatement).isPresence()) {
+ return "!";
+ }
+ } else if (yangStatement instanceof MultiInstancesDataNode) {
+ StringBuilder sb = new StringBuilder("*");
+ if (yangStatement instanceof YangList) {
+ YangList yangList = (YangList) yangStatement;
+ if (yangList.getKey() != null) {
+ sb.append(" [");
+ sb.append(yangList.getKey().getArgStr());
+ sb.append("]");
+ }
+ }
+ return sb.toString();
+ }
+ return "";
+ }
+
+ private String getType(TypedDataNode typedDataNode) {
+ if (typedDataNode.getType().getRestriction() instanceof LeafRef) {
+ LeafRef leafRef = (LeafRef) typedDataNode.getType().getRestriction();
+ return "-> " + leafRef.getEffectivePath().getArgStr();
+ } else {
+ return typedDataNode.getType().getArgStr();
+ }
+ }
+
+ private String getFeatures(IfFeatureSupport ifFeatureSupport) {
+ StringBuilder sb = new StringBuilder();
+ List<IfFeature> ifFeatures = ifFeatureSupport.getIfFeatures();
+ if (!ifFeatures.isEmpty()) {
+ sb.append(" {");
+ int size = ifFeatures.size();
+ for (int i = 0; i < size; i++) {
+ IfFeature ifFeature = ifFeatures.get(i);
+ sb.append(ifFeature.getArgStr());
+ if (i != (size - 1)) {
+ sb.append(",");
+ }
+ }
+ sb.append("}?");
+ }
+ return sb.toString();
+ }
+
+ private String wrapLongPath(String offSet, String longPath) {
+ if ((offSet.length() + longPath.length()) <= lineLength) {
+ return offSet + longPath;
+ }
+ StringBuilder wrappedLine = new StringBuilder(offSet);
+ String firstCandidatePath = longPath.substring(0, lineLength - offSet.length());
+ int index = firstCandidatePath.lastIndexOf("/");
+ firstCandidatePath = firstCandidatePath.substring(0, index);
+ wrappedLine.append(firstCandidatePath);
+ wrappedLine.append("\n");
+ String nextOffSet = offSet + " ";
+ String nextLongPath = longPath.substring(index);
+ wrappedLine.append(wrapLongPath(nextOffSet, nextLongPath));
+ return wrappedLine.toString();
+ }
+
+ /**
+ * build augmentation representation string.
+ * @param augment augment
+ * @param offSet offset
+ * @return string
+ */
+ public String buildAugmentRepresentation(Augment augment, String offSet) {
+ StringBuilder sb = new StringBuilder(offSet);
+ int beginIndex = sb.length();
+ sb.append("augment");
+ sb.append(" ");
+ int nameIndex = sb.length();
+ sb.append(augment.getArgStr());
+ sb.append(":\n");
+ if (sb.length() > lineLength) {
+ String subString = sb.substring(0, lineLength);
+ int index = subString.lastIndexOf("/");
+ StringBuilder newSb = new StringBuilder();
+ String firstLine = sb.substring(0, index);
+ newSb.append(firstLine);
+ newSb.append("\n");
+ newSb.append(offSet);
+ for (int i = beginIndex; i < (nameIndex + 2); i++) {
+ newSb.append(" ");
+ }
+ newSb.append(sb.substring(index));
+ return newSb.toString();
+ }
+ return sb.toString();
+ }
+
+ /**
+ * build a node representation from yang statement.
+ * @param yangStatement yang statement.
+ * @param offSet offset.
+ * @return string
+ */
+ public String buildNodeRepresentation(YangStatement yangStatement, String offSet) {
+ StringBuilder sb = new StringBuilder(offSet);
+ int beginIndex = sb.length();
+ //status
+ sb.append(getStatus(yangStatement)).append("--");
+ //flags
+ sb.append(getFlags(yangStatement));
+ //name
+ String name = getNodeName(yangStatement);
+ int nameIndex = sb.length();
+ if (name.startsWith(" ")) {
+ nameIndex++;
+ }
+ sb.append(name);
+ sb.append(getOpts(yangStatement));
+
+
+ if (yangStatement instanceof TypedDataNode) {
+ int typeIndex = sb.length();
+ TypedDataNode typedDataNode = (TypedDataNode) yangStatement;
+ String type = getType(typedDataNode);
+ if (type.length() + typeIndex + 1 > lineLength) {
+ //change line
+ StringBuilder newLine = new StringBuilder();
+
+ StringBuilder newOffSet = new StringBuilder(offSet);
+
+ for (int i = beginIndex; i < nameIndex + 2; i++) {
+ newOffSet.append(" ");
+ }
+ newLine.append(newOffSet);
+ newLine.append(type);
+
+ if ((typedDataNode.getType().getRestriction() instanceof LeafRef)
+ && (newLine.length() > lineLength)) {
+ sb.append(" ");
+ sb.append("leafref");
+ } else {
+ sb.append("\n");
+ sb.append(newLine);
+ }
+
+
+ } else {
+ sb.append(" ");
+ sb.append(type);
+ }
+ }
+
+ if (yangStatement instanceof IfFeatureSupport) {
+ IfFeatureSupport ifFeatureSupport = (IfFeatureSupport) yangStatement;
+ String features = getFeatures(ifFeatureSupport);
+ if (features.length() > 0) {
+ int ifFeatureIndex = sb.length();
+ int lastCrIndex = sb.lastIndexOf("\n");
+ if (lastCrIndex == -1) {
+ lastCrIndex = 0;
+ }
+ if (((ifFeatureIndex - lastCrIndex) + features.length()) > lineLength) {
+ //change line
+ sb.append("\n");
+ sb.append(offSet);
+ for (int i = beginIndex; i < (nameIndex + 2); i++) {
+ sb.append(" ");
+ }
+ sb.append(features);
+ } else {
+ sb.append(" ");
+ sb.append(features);
+ }
+ }
+
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ @Override
+ public YangCompilerPluginParameter getParameter(Properties compilerProps, String name, String value)
+ throws YangCompilerException {
+ if (!name.equals("output") && !name.equals("line-length")
+ && !name.equals("expand-grouping")) {
+ throw new YangCompilerException("unrecognized parameter:" + name);
+ }
+ if (name.equals("output")) {
+ return YangCompilerPlugin.super.getParameter(compilerProps, name, value);
+ }
+ YangCompilerPluginParameter yangCompilerPluginParameter = new YangCompilerPluginParameter() {
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Object getValue() {
+
+ if (name.equals("line-length")) {
+ return Integer.parseInt(value);
+ }
+
+ if (name.equals("expand-grouping")) {
+ return Boolean.valueOf(value);
+ }
+ return null;
+ }
+
+ };
+ return yangCompilerPluginParameter;
+
+
+ }
+
+ @Override
+ public void run(YangSchemaContext schemaContext, YangCompiler yangCompiler,
+ List<YangCompilerPluginParameter> parameters) throws YangCompilerException {
+ for (YangCompilerPluginParameter parameter : parameters) {
+ if (parameter.getName().equals("output")) {
+ output = (String) parameter.getValue();
+ } else if (parameter.getName().equals("line-length")) {
+ lineLength = (int) parameter.getValue();
+ } else if (parameter.getName().equals("expand-grouping")) {
+ expandGrouping = (boolean) parameter.getValue();
+ }
+ }
+ if (output == null) {
+ throw new YangCompilerException("missing mandatory parameter:output");
+ }
+ File outputDir = new File(output);
+ if (!outputDir.exists()) {
+ outputDir.mkdirs();
+ }
+
+ List<Module> modules = schemaContext.getModules();
+ for (Module module : modules) {
+ String yangTree = buildYangTree(module);
+ FileUtil.writeUtf8File(yangTree, new File(outputDir,
+ module.getArgStr()
+ + (module.getCurRevisionDate().isPresent() ? "@" + module.getCurRevisionDate().get() : "")
+ + "_tree.txt"));
+ }
+ }
+}