summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java2
-rwxr-xr-xioam/impl/src/main/java/io/fd/hc2vpp/vppioam/impl/VppIoamModule.java4
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/NatModule.java4
-rwxr-xr-xnsh/impl/src/main/java/io/fd/hc2vpp/vppnsh/impl/VppNshModule.java4
-rw-r--r--release-notes/pom.xml45
-rw-r--r--release-notes/src/main/asciidoc/api_docs/api_docs.adoc3
-rw-r--r--release-notes/src/main/asciidoc/api_docs/api_docs_index.adoc19
-rw-r--r--release-notes/src/main/asciidoc/release_notes.adoc4
-rw-r--r--vpp-integration/api-docs/api/asciidoc/Readme.adoc13
-rw-r--r--vpp-integration/api-docs/api/pom.xml33
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/CoverageUnit.java124
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/JavaApiMessage.java56
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/Operation.java93
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/PluginCoverage.java85
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/VppApiMessage.java69
-rw-r--r--vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/YangType.java66
-rw-r--r--vpp-integration/api-docs/asciidoc/Readme.adoc3
-rw-r--r--vpp-integration/api-docs/core/asciidoc/Readme.adoc3
-rw-r--r--vpp-integration/api-docs/core/pom.xml112
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ClassPathTypeIndex.java74
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CollectingWriterBuilder.java153
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java184
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageScanner.java74
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/LinkGenerator.java33
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodDelegatingClassVisitor.java54
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodPluginCoverageVisitor.java90
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelLinkIndex.java71
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelTypeIndex.java88
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/PluginMethodReference.java56
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/VppApiUtils.java43
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangModelKey.java73
-rw-r--r--vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangTypeLinkIndex.java56
-rw-r--r--vpp-integration/api-docs/docs/pom.xml92
-rw-r--r--vpp-integration/api-docs/pom.xml40
-rw-r--r--vpp-integration/api-docs/scripts/pom.xml192
-rw-r--r--vpp-integration/api-docs/scripts/src/main/groovy/io/fd/hc2vpp/docs/scripts/ApiDocsIndexGenerator.groovy156
-rw-r--r--vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockAclModule.java48
-rw-r--r--vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockBindingModule.java49
-rw-r--r--vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockIoamModule.java73
-rw-r--r--vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNatModule.java48
-rw-r--r--vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNshModule.java48
-rw-r--r--vpp-integration/api-docs/scripts/src/main/resources/routing.json4
-rw-r--r--vpp-integration/api-docs/scripts/src/main/resources/vpp-management.json3
-rw-r--r--vpp-integration/api-docs/scripts/src/main/resources/yang_to_jvpp_template6
-rw-r--r--vpp-integration/pom.xml1
45 files changed, 2543 insertions, 8 deletions
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java
index a97f57ec1..afb7da669 100644
--- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java
+++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java
@@ -52,7 +52,7 @@ public class AclModule extends AbstractModule {
}
@VisibleForTesting
- AclModule(@Nonnull final Class<? extends Provider<FutureJVppAclFacade>> jvppAclProviderClass) {
+ protected AclModule(@Nonnull final Class<? extends Provider<FutureJVppAclFacade>> jvppAclProviderClass) {
this.jvppAclProviderClass = jvppAclProviderClass;
}
diff --git a/ioam/impl/src/main/java/io/fd/hc2vpp/vppioam/impl/VppIoamModule.java b/ioam/impl/src/main/java/io/fd/hc2vpp/vppioam/impl/VppIoamModule.java
index 4c143131c..1feaf9a68 100755
--- a/ioam/impl/src/main/java/io/fd/hc2vpp/vppioam/impl/VppIoamModule.java
+++ b/ioam/impl/src/main/java/io/fd/hc2vpp/vppioam/impl/VppIoamModule.java
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
/*
* Glue code necessary for Honeycomb distribution to pick up the plugin classes
*/
-public final class VppIoamModule extends AbstractModule {
+public class VppIoamModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(VppIoamModule.class);
private final Class<? extends Provider<FutureJVppIoamtraceFacade>> jvppIoamTraceProviderClass;
@@ -52,7 +52,7 @@ public final class VppIoamModule extends AbstractModule {
}
@VisibleForTesting
- VppIoamModule(Class<? extends Provider<FutureJVppIoamtraceFacade>> jvppIoamTraceProvider,
+ protected VppIoamModule(Class<? extends Provider<FutureJVppIoamtraceFacade>> jvppIoamTraceProvider,
Class<? extends Provider<FutureJVppIoampotFacade>> jvppIoamPotProviderClass,
Class<? extends Provider<FutureJVppIoamexportFacade>> jvppIoamExportProviderClass) {
this.jvppIoamTraceProviderClass = jvppIoamTraceProvider;
diff --git a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/NatModule.java b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/NatModule.java
index cf6c3bc22..fece7b011 100644
--- a/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/NatModule.java
+++ b/nat/nat2vpp/src/main/java/io/fd/hc2vpp/nat/NatModule.java
@@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
/**
* Module class instantiating nat plugin components.
*/
-public final class NatModule extends AbstractModule {
+public class NatModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(NatModule.class);
private final Class<? extends Provider<FutureJVppSnatFacade>> jvppSnatProviderClass;
@@ -48,7 +48,7 @@ public final class NatModule extends AbstractModule {
}
@VisibleForTesting
- NatModule(Class<? extends Provider<FutureJVppSnatFacade>> jvppSnatProvider) {
+ protected NatModule(Class<? extends Provider<FutureJVppSnatFacade>> jvppSnatProvider) {
this.jvppSnatProviderClass = jvppSnatProvider;
}
diff --git a/nsh/impl/src/main/java/io/fd/hc2vpp/vppnsh/impl/VppNshModule.java b/nsh/impl/src/main/java/io/fd/hc2vpp/vppnsh/impl/VppNshModule.java
index 1964fafe0..aaa1d6c4e 100755
--- a/nsh/impl/src/main/java/io/fd/hc2vpp/vppnsh/impl/VppNshModule.java
+++ b/nsh/impl/src/main/java/io/fd/hc2vpp/vppnsh/impl/VppNshModule.java
@@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory;
/**
* This is some glue code necessary for Honeycomb distribution to pick up the plugin classes
*/
-public final class VppNshModule extends AbstractModule {
+public class VppNshModule extends AbstractModule {
private static final Logger LOG = LoggerFactory.getLogger(VppNshModule.class);
private final Class<? extends Provider<FutureJVppNshFacade>> jvppNshProviderClass;
@@ -45,7 +45,7 @@ public final class VppNshModule extends AbstractModule {
this(JVppNshProvider.class);
}
@VisibleForTesting
- VppNshModule(Class<? extends Provider<FutureJVppNshFacade>> jvppNshProvider) {
+ protected VppNshModule(Class<? extends Provider<FutureJVppNshFacade>> jvppNshProvider) {
this.jvppNshProviderClass = jvppNshProvider;
}
diff --git a/release-notes/pom.xml b/release-notes/pom.xml
index 1fc670f31..c34c7b45c 100644
--- a/release-notes/pom.xml
+++ b/release-notes/pom.xml
@@ -31,6 +31,14 @@
<modelVersion>4.0.0</modelVersion>
<description>Hc2vpp release notes</description>
+ <dependencies>
+ <dependency>
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>docs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
<!-- Do not push, this is just a documentation producer -->
<build>
<plugins>
@@ -50,6 +58,25 @@
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>unpack-configuration</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includes>*.adoc</includes>
+ <outputDirectory>${project.build.directory}/raw-adoc/api_docs</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>${asciidoctor.maven.plugin.version}</version>
@@ -63,6 +90,9 @@
<configuration>
<!-- https://github.com/asciidoctor/asciidoctor-maven-plugin -->
<!-- http://asciidoctor.org/docs/asciidoc-syntax-quick-reference -->
+ <!-- raw-adoc folder combines docs from src folder + generated api docs files,
+ in order to have them all available while generating site -->
+ <baseDir>${project.build.directory}/raw-adoc</baseDir>
<backend>html5</backend>
<doctype>docbook</doctype>
<sourceHighlighter>coderay</sourceHighlighter>
@@ -101,6 +131,21 @@
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
+ <id>copy-raw-adoc</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/raw-adoc</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/src/main/asciidoc/</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
<id>copy-release-notes-to-site</id>
<phase>site</phase>
<goals>
diff --git a/release-notes/src/main/asciidoc/api_docs/api_docs.adoc b/release-notes/src/main/asciidoc/api_docs/api_docs.adoc
new file mode 100644
index 000000000..5d519c68d
--- /dev/null
+++ b/release-notes/src/main/asciidoc/api_docs/api_docs.adoc
@@ -0,0 +1,3 @@
+== API documentation
+
+link:api_docs_index.html[VPP API to Yang index]
diff --git a/release-notes/src/main/asciidoc/api_docs/api_docs_index.adoc b/release-notes/src/main/asciidoc/api_docs/api_docs_index.adoc
new file mode 100644
index 000000000..08dfeb28f
--- /dev/null
+++ b/release-notes/src/main/asciidoc/api_docs/api_docs_index.adoc
@@ -0,0 +1,19 @@
+== VPP api to Yang index
+
+// TODO - generate this file based on list of JVPP plugins used
+
+Mapping between VPP binary apis and JVpp binding in hc2vpp
+
+include::api_docs/futurejvppcore-yang-config-index.adoc[JVpp Core plugin docs]
+
+include::api_docs/futurejvppacl-yang-config-index.adoc[JVpp Acl plugin docs]
+
+include::api_docs/futurejvppsnat-yang-config-index.adoc[JVpp Snat plugin docs]
+
+include::api_docs/futurejvppnsh-yang-config-index.adoc[JVpp Nsh plugin docs]
+
+include::api_docs/futurejvppioamtrace-yang-config-index.adoc[JVpp Ioam Trace plugin docs]
+
+include::api_docs/futurejvppioampot-yang-config-index.adoc[JVpp Ioam Pot plugin docs]
+
+include::api_docs/futurejvppioamexport-yang-config-index.adoc[JVpp Ioam Export plugin docs]
diff --git a/release-notes/src/main/asciidoc/release_notes.adoc b/release-notes/src/main/asciidoc/release_notes.adoc
index 7471cda9d..7f9c84a82 100644
--- a/release-notes/src/main/asciidoc/release_notes.adoc
+++ b/release-notes/src/main/asciidoc/release_notes.adoc
@@ -26,4 +26,6 @@ include::install_guide/install_guide.adoc[]
include::user_guide/user_guide.adoc[]
-include::devel_guide/devel_guide.adoc[] \ No newline at end of file
+include::devel_guide/devel_guide.adoc[]
+
+include::api_docs/api_docs.adoc[] \ No newline at end of file
diff --git a/vpp-integration/api-docs/api/asciidoc/Readme.adoc b/vpp-integration/api-docs/api/asciidoc/Readme.adoc
new file mode 100644
index 000000000..145404972
--- /dev/null
+++ b/vpp-integration/api-docs/api/asciidoc/Readme.adoc
@@ -0,0 +1,13 @@
+= docs-api
+
+Defines general api for VPP binary api coverage
+
+== Elements
+
+* PluginCoverage - Contains coverage data for single JVPP plugin, including supported
+ VPP binary equivalents in JVpp, what Yang nodes are bind to such api and what operations are
+ supported
+* VppApiMessage - Reference to single VPP binary api with link to its documentation
+* JavaApiMessage - Reference to JVpp equivalent of VPP binary api
+* YangType - Reference to single Yang type with link to its model
+* Operation - reference to single CRUD operation with link to binding class \ No newline at end of file
diff --git a/vpp-integration/api-docs/api/pom.xml b/vpp-integration/api-docs/api/pom.xml
new file mode 100644
index 000000000..9c40d1f65
--- /dev/null
+++ b/vpp-integration/api-docs/api/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<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">
+ <parent>
+ <artifactId>hc2vpp-parent</artifactId>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <version>1.17.10-SNAPSHOT</version>
+ <relativePath>../../../common/hc2vpp-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>docs-api</artifactId>
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <version>1.17.10-SNAPSHOT</version>
+
+</project> \ No newline at end of file
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/CoverageUnit.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/CoverageUnit.java
new file mode 100644
index 000000000..06cb59f69
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/CoverageUnit.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents mapping between single supported VPP binary api and its binding
+ */
+public class CoverageUnit {
+
+ /**
+ * VPP binary api reference
+ */
+ private final VppApiMessage vppApi;
+
+ /**
+ * Java equivalent of VPP binary api
+ */
+ private final JavaApiMessage javaApi;
+
+ /**
+ * Yang types used to bind this request
+ */
+ private final List<YangType> yangTypes;
+
+ /**
+ * Operations supported for this api
+ */
+ private final List<Operation> supportedOperations;
+
+ private CoverageUnit(final VppApiMessage vppApi, final JavaApiMessage javaApi,
+ final List<YangType> yangTypes,
+ final List<Operation> supportedOperations) {
+ this.vppApi = vppApi;
+ this.javaApi = javaApi;
+ this.yangTypes = yangTypes;
+ this.supportedOperations = supportedOperations;
+ }
+
+ public VppApiMessage getVppApi() {
+ return vppApi;
+ }
+
+ public JavaApiMessage getJavaApi() {
+ return javaApi;
+ }
+
+ public List<YangType> getYangTypes() {
+ return yangTypes;
+ }
+
+ public List<Operation> getSupportedOperations() {
+ return supportedOperations;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final CoverageUnit that = (CoverageUnit) o;
+
+ return Objects.equals(this.vppApi, that.vppApi) &&
+ Objects.equals(this.javaApi, that.javaApi) &&
+ Objects.equals(this.yangTypes, that.yangTypes) &&
+ Objects.equals(this.supportedOperations, that.supportedOperations);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(vppApi, javaApi, yangTypes, supportedOperations);
+ }
+
+ public static class CoverageUnitBuilder {
+ private VppApiMessage vppApi;
+ private JavaApiMessage javaApi;
+ private List<YangType> yangTypes;
+ private List<Operation> supportedOperations;
+
+ public CoverageUnitBuilder setVppApi(final VppApiMessage vppApi) {
+ this.vppApi = vppApi;
+ return this;
+ }
+
+ public CoverageUnitBuilder setJavaApi(final JavaApiMessage javaApi) {
+ this.javaApi = javaApi;
+ return this;
+ }
+
+ public CoverageUnitBuilder setYangTypes(final List<YangType> yangTypes) {
+ this.yangTypes = yangTypes;
+ return this;
+ }
+
+ public CoverageUnitBuilder setSupportedOperations(final List<Operation> supportedOperations) {
+ this.supportedOperations = supportedOperations;
+ return this;
+ }
+
+ public CoverageUnit build() {
+ return new CoverageUnit(vppApi, javaApi, yangTypes, supportedOperations);
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/JavaApiMessage.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/JavaApiMessage.java
new file mode 100644
index 000000000..db4575c5a
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/JavaApiMessage.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.Objects;
+
+/**
+ * Reference of Java equivalent of VPP binary api
+ */
+public class JavaApiMessage {
+
+ /**
+ * Name of the call
+ */
+ private final String api;
+
+ public JavaApiMessage(final String api) {
+ this.api = api;
+ }
+
+ public String getApi() {
+ return api;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final JavaApiMessage that = (JavaApiMessage) o;
+ return Objects.equals(this.api, that.api);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(api);
+ }
+}
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/Operation.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/Operation.java
new file mode 100644
index 000000000..e471fb6bf
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/Operation.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.Objects;
+
+/**
+ * Reference to single crud operation
+ */
+public class Operation {
+
+ /**
+ * Git link to class that performs referenced operation
+ */
+ private final String link;
+ //TODO - investigate option to link directly to line number
+
+ /**
+ * Type of crud operation
+ */
+ private final CrudOperation operation;
+
+ public Operation(final String link, final CrudOperation operation) {
+ this.link = link;
+ this.operation = operation;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ public CrudOperation getOperation() {
+ return operation;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final Operation that = (Operation) o;
+
+ return Objects.equals(this.link, that.link) &&
+ Objects.equals(this.operation, that.operation);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(link, operation);
+ }
+
+ public enum CrudOperation {
+ WRITE("Write", "writeCurrentAttributes"),
+ UPDATE("Update", "updateCurrentAttributes"),
+ DELETE("Delete", "deleteCurrentAttributes"),
+ READ_ALL("Read all", "getAllIds"),
+ READ_ONE("Read details", "readCurrentAttributes");
+
+ private final String displayName;
+ private final String methodReference;
+
+ CrudOperation(final String displayName, final String methodReference) {
+ this.displayName = displayName;
+ this.methodReference = methodReference;
+ }
+
+ public String getMethodReference() {
+ return methodReference;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/PluginCoverage.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/PluginCoverage.java
new file mode 100644
index 000000000..8e62e9ca3
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/PluginCoverage.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents coverage data for single VPP plugin
+ */
+public class PluginCoverage {
+
+ /**
+ * Name of the covered plugin
+ */
+ private final String pluginName;
+
+ /**
+ * Coverage data
+ */
+ private final Set<CoverageUnit> coverage;
+
+ /**
+ * Whether this is config or operational coverage
+ */
+ private final boolean isConfig;
+
+ public PluginCoverage(final String pluginName, final Set<CoverageUnit> coverage, final boolean isConfig) {
+ this.pluginName = pluginName;
+ this.coverage = coverage;
+ this.isConfig = isConfig;
+ }
+
+ public String getPluginName() {
+ return pluginName;
+ }
+
+ public Set<CoverageUnit> getCoverage() {
+ return coverage;
+ }
+
+ public boolean isConfig() {
+ return isConfig;
+ }
+
+ public boolean hasCoverage() {
+ return !coverage.isEmpty();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final PluginCoverage that = (PluginCoverage) o;
+
+ return Objects.equals(this.isConfig, that.isConfig) &&
+ Objects.equals(this.pluginName, that.pluginName) &&
+ Objects.equals(this.coverage, that.coverage);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.pluginName, this.coverage, this.isConfig);
+ }
+}
+
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/VppApiMessage.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/VppApiMessage.java
new file mode 100644
index 000000000..78010471a
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/VppApiMessage.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.Objects;
+
+/**
+ * Represents reference to VPP binary api
+ */
+public class VppApiMessage {
+
+ /**
+ * Name of the api
+ */
+ private final String name;
+
+ /**
+ * fd.io doc link
+ */
+ // TODO - check if possible to add direct link for specific api
+ private final String link;
+
+ public VppApiMessage(final String name, final String link) {
+ this.name = name;
+ this.link = link;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final VppApiMessage that = (VppApiMessage) o;
+
+ return Objects.equals(this.name, that.name) && Objects.equals(this.link, that.link);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, link);
+ }
+}
diff --git a/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/YangType.java b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/YangType.java
new file mode 100644
index 000000000..a2585acf6
--- /dev/null
+++ b/vpp-integration/api-docs/api/src/main/java/io/fd/hc2vpp/docs/api/YangType.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.api;
+
+import java.util.Objects;
+
+/**
+ * Represents Yang type used to bind VPP api's
+ */
+public class YangType {
+
+ /**
+ * Fully qualified name of Yang type
+ */
+ private final String type;
+
+ /**
+ * Git link to its model origin
+ */
+ private final String link;
+
+ public YangType(final String type, final String link) {
+ this.type = type;
+ this.link = link;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getLink() {
+ return link;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final YangType that = (YangType) o;
+ return Objects.equals(this.type, that.type) && !Objects.equals(this.link, that.link);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, link);
+ }
+}
diff --git a/vpp-integration/api-docs/asciidoc/Readme.adoc b/vpp-integration/api-docs/asciidoc/Readme.adoc
new file mode 100644
index 000000000..b0964c29a
--- /dev/null
+++ b/vpp-integration/api-docs/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= api-docs
+
+Overview of api-docs \ No newline at end of file
diff --git a/vpp-integration/api-docs/core/asciidoc/Readme.adoc b/vpp-integration/api-docs/core/asciidoc/Readme.adoc
new file mode 100644
index 000000000..919d9c4dc
--- /dev/null
+++ b/vpp-integration/api-docs/core/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= docs-core
+
+Overview of docs-core \ No newline at end of file
diff --git a/vpp-integration/api-docs/core/pom.xml b/vpp-integration/api-docs/core/pom.xml
new file mode 100644
index 000000000..0d691b424
--- /dev/null
+++ b/vpp-integration/api-docs/core/pom.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<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">
+ <parent>
+ <artifactId>hc2vpp-parent</artifactId>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <version>1.17.10-SNAPSHOT</version>
+ <relativePath>../../../common/hc2vpp-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>docs-core</artifactId>
+ <version>1.17.10-SNAPSHOT</version>
+
+ <properties>
+ <mockito-core.version>1.10.19</mockito-core.version>
+ <junit.version>4.12</junit.version>
+ <guice.version>4.1.0</guice.version>
+ <asm.version>5.2</asm.version>
+ <asciidoctorj.version>1.5.4</asciidoctorj.version>
+ <slf4j-simple.version>1.7.25</slf4j-simple.version>
+ <jvpp.version>17.10-SNAPSHOT</jvpp.version>
+ <guava.version>19.0</guava.version>
+ <reflections.version>0.9.11</reflections.version>
+
+ <coverage.modules/>
+ <!-- If covered project is lower that 2 levels under root, must be overridden -->
+ <project.root.folder>${project.basedir}/../..</project.root.folder>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>docs-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-core</artifactId>
+ <version>${jvpp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-registry</artifactId>
+ <version>${jvpp.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <version>${asm.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>${guice.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>${mockito-core.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>${reflections.version}</version>
+ </dependency>
+
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ClassPathTypeIndex.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ClassPathTypeIndex.java
new file mode 100644
index 000000000..e204d6321
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ClassPathTypeIndex.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * Index of java classes to relative absolute paths within repository. Used to generate Git links for binding classes of
+ * VPP apis
+ */
+public class ClassPathTypeIndex implements LinkGenerator {
+
+ private static final String JAVA_SOURCE_FOLDER = "src/main/java";
+ private static final int JAVA_SOURCE_FOLDER_NAME_LENGTH = JAVA_SOURCE_FOLDER.length() + 1;
+
+ /**
+ * <li>key - fully qualified class name value</li><li>value - path within codebase/repository</li>
+ */
+ private final Map<String, String> index;
+
+ public ClassPathTypeIndex(final String projectRoot, final String version) {
+ index = buildIndex(projectRoot, version);
+ }
+
+ /**
+ * <li>input format - LOCAL_ROOT/hc2vpp/module/src/main/java/fully/qualified/class/name/Class.java</li><li>output
+ * format - fully.qualified.class.name.Class</li>
+ */
+ private static String key(String raw) {
+ return raw.substring(raw.indexOf(JAVA_SOURCE_FOLDER) + JAVA_SOURCE_FOLDER_NAME_LENGTH)
+ .replace("/", ".")
+ .replace(".java", "");
+ }
+
+ public String linkForClass(final String clazz) {
+ return index.get(clazz.replace("/", "."));
+ }
+
+ private Map<String, String> buildIndex(final String projectRoot, final String version) {
+ try {
+ return Files.walk(Paths.get(projectRoot))
+ .filter(path -> path.toString().contains("src/main/java"))
+ .filter(path -> path.toString().endsWith(".java"))
+ .map(Path::toString)
+ .map(s -> s.replace(projectRoot, ""))
+ .distinct()
+ .collect(Collectors.toMap(ClassPathTypeIndex::key, o -> generateLink(o, version)));
+ } catch (IOException e) {
+ throw new IllegalStateException(format("%s not found", projectRoot), e);
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CollectingWriterBuilder.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CollectingWriterBuilder.java
new file mode 100644
index 000000000..b8fcc8b03
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CollectingWriterBuilder.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder;
+import io.fd.honeycomb.translate.write.Writer;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Implementations of builder that collects handlers as they are bind
+ */
+public class CollectingWriterBuilder implements ModifiableWriterRegistryBuilder {
+
+ private final List<Writer<? extends DataObject>> singleNodeHandlers;
+ private final List<MultiNodeWriteHandler> multiNodeWriteHandlers;
+
+ public CollectingWriterBuilder() {
+ singleNodeHandlers = new LinkedList<>();
+ multiNodeWriteHandlers = new LinkedList<>();
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> add(
+ @Nonnull Writer<? extends DataObject> handler) {
+ singleNodeHandlers.add(handler);
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> subtreeAdd(
+ @Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull Writer<? extends DataObject> handler) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, handledChildren));
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> addBefore(
+ @Nonnull Writer<? extends DataObject> handler, @Nonnull InstanceIdentifier<?> relatedType) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, Collections.singleton(relatedType)));
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> addBefore(
+ @Nonnull Writer<? extends DataObject> handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) {
+ singleNodeHandlers.add(handler);
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> subtreeAddBefore(
+ @Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull Writer<? extends DataObject> handler,
+ @Nonnull InstanceIdentifier<?> relatedType) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, handledChildren));
+ return null;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> subtreeAddBefore(
+ @Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull Writer<? extends DataObject> handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, handledChildren));
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> addAfter(
+ @Nonnull Writer<? extends DataObject> handler, @Nonnull InstanceIdentifier<?> relatedType) {
+ singleNodeHandlers.add(handler);
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> addAfter(
+ @Nonnull Writer<? extends DataObject> handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) {
+ singleNodeHandlers.add(handler);
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> subtreeAddAfter(
+ @Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull Writer<? extends DataObject> handler,
+ @Nonnull InstanceIdentifier<?> relatedType) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, Collections.singleton(relatedType)));
+ return this;
+ }
+
+ @Override
+ public ModifiableSubtreeManagerRegistryBuilder<Writer<? extends DataObject>> subtreeAddAfter(
+ @Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull Writer<? extends DataObject> handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) {
+ multiNodeWriteHandlers.add(new MultiNodeWriteHandler(handler, handledChildren));
+ return this;
+ }
+
+ public List<Writer<? extends DataObject>> getSingleNodeHandlers() {
+ return singleNodeHandlers;
+ }
+
+ public List<MultiNodeWriteHandler> getMultiNodeWriteHandlers() {
+ return multiNodeWriteHandlers;
+ }
+
+ public static class MultiNodeWriteHandler {
+ private final Writer<? extends DataObject> writer;
+ private final Set<String> handledChildren;
+
+
+ public MultiNodeWriteHandler(Writer<? extends DataObject> writer, Set<InstanceIdentifier<?>> handledChildren) {
+ this.writer = writer;
+ this.handledChildren = ImmutableSet.<String>builder()
+ .add(writer.getManagedDataObjectType().getTargetType().getName())
+ .addAll(handledChildren.stream()
+ .map(InstanceIdentifier::getTargetType)
+ .map(Class::getName)
+ .collect(Collectors.toSet()))
+ .build();
+ }
+
+ public Writer<? extends DataObject> getWriter() {
+ return writer;
+ }
+
+ public Set<String> getHandledChildren() {
+ return handledChildren;
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java
new file mode 100644
index 000000000..4b6ab776c
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+
+import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.DELETE;
+import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.UPDATE;
+import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.WRITE;
+import static java.lang.String.format;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+import io.fd.hc2vpp.docs.api.CoverageUnit;
+import io.fd.hc2vpp.docs.api.JavaApiMessage;
+import io.fd.hc2vpp.docs.api.Operation;
+import io.fd.hc2vpp.docs.api.PluginCoverage;
+import io.fd.hc2vpp.docs.api.YangType;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.reflections.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CoverageGenerator implements VppApiUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CoverageGenerator.class);
+
+ private final CollectingWriterBuilder writerBuilder;
+
+ public CoverageGenerator() {
+ writerBuilder = new CollectingWriterBuilder();
+ }
+
+ public PluginCoverage generateConfigCoverage(final Class<?> pluginClass,
+ final String version,
+ final List<Module> scannedModules,
+ final YangTypeLinkIndex yangTypeIndex,
+ final ClassPathTypeIndex classPathIndex) {
+ LOG.info("Generating config coverage for plugin {}", pluginClass);
+ getInjectedWriterFactories(scannedModules).forEach(writerFactory -> writerFactory.init(writerBuilder));
+
+ LOG.info("Processing single node handlers");
+ final Set<CoverageUnit> singleNodeCoverageUnits = writerBuilder.getSingleNodeHandlers().stream()
+ .flatMap(writer -> {
+ // extracts customizer class from handler
+ final Class<?> customizerClass = getCustomizerClass(writer);
+
+ // scans within write method
+ final Set<PluginMethodReference> writeReferences =
+ new CoverageScanner(customizerClass, WRITE, pluginClass).scan();
+
+ // scans within update method
+ final Set<PluginMethodReference> updateReferences =
+ new CoverageScanner(customizerClass, UPDATE, pluginClass).scan();
+
+ // scans within delete method
+ final Set<PluginMethodReference> deleteReferences =
+ new CoverageScanner(customizerClass, DELETE, pluginClass).scan();
+
+ return Stream.of(writeReferences.stream(), updateReferences.stream(), deleteReferences.stream())
+ .flatMap(pluginMethodReferences -> pluginMethodReferences)
+ .map(reference -> {
+ final CoverageUnit.CoverageUnitBuilder builder = new CoverageUnit.CoverageUnitBuilder();
+
+ // binds vpp api name and generateLink bind with version
+ builder.setVppApi(fromJvppApi(version, reference));
+
+ //binds java api reference
+ builder.setJavaApi(new JavaApiMessage(reference.getName()));
+
+ //binds Yang types with links from pre-build index
+ // TODO - use deserialized yii
+ final String typeName = writer.getManagedDataObjectType().getTargetType().getTypeName();
+ builder.setYangTypes(Collections.singletonList(new YangType(
+ typeName,
+ yangTypeIndex.getLinkForType(typeName))));
+
+ final List<Operation> supportedOperations = new LinkedList<>();
+
+ final String callerClassLink = classPathIndex.linkForClass(reference.getCaller());
+ if (writeReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, WRITE));
+ }
+
+ if (updateReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, UPDATE));
+ }
+
+ if (deleteReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, DELETE));
+ }
+ return builder.setSupportedOperations(supportedOperations).build();
+ });
+ }).collect(Collectors.toSet());
+
+ LOG.info("Processing multi node handlers");
+ final Set<CoverageUnit> multiNodeCoverageUnits = writerBuilder.getMultiNodeWriteHandlers().stream()
+ .flatMap(handler -> {
+ final Class<?> customizerClass = getCustomizerClass(handler.getWriter());
+ final Set<PluginMethodReference> writeReferences =
+ new CoverageScanner(customizerClass, WRITE, pluginClass).scan();
+
+ final Set<PluginMethodReference> updateReferences =
+ new CoverageScanner(customizerClass, UPDATE, pluginClass).scan();
+
+ final Set<PluginMethodReference> deleteReferences =
+ new CoverageScanner(customizerClass, DELETE, pluginClass).scan();
+
+ return Stream.of(writeReferences.stream(), updateReferences.stream(), deleteReferences.stream())
+ .flatMap(pluginMethodReferenceStream -> pluginMethodReferenceStream)
+ .map(reference -> {
+ final CoverageUnit.CoverageUnitBuilder builder = new CoverageUnit.CoverageUnitBuilder();
+ builder.setVppApi(fromJvppApi(version, reference));
+ builder.setJavaApi(new JavaApiMessage(reference.getName()));
+
+ builder.setYangTypes(handler.getHandledChildren().stream()
+ .map(type -> new YangType(type, yangTypeIndex.getLinkForType(type)))
+ .collect(Collectors.toList()));
+
+ final String callerClassLink = classPathIndex.linkForClass(reference.getCaller());
+ final List<Operation> supportedOperations = new LinkedList<>();
+ if (writeReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, WRITE));
+ }
+
+ if (updateReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, UPDATE));
+ }
+
+ if (deleteReferences.contains(reference)) {
+ supportedOperations.add(new Operation(callerClassLink, DELETE));
+ }
+ return builder.setSupportedOperations(supportedOperations).build();
+ });
+ }).collect(Collectors.toSet());
+
+ return new PluginCoverage(pluginClass.getSimpleName(),
+ Stream.of(singleNodeCoverageUnits.stream(), multiNodeCoverageUnits.stream())
+ .flatMap(coverageUnitStream -> coverageUnitStream)
+ .collect(Collectors.toSet()), true);
+ }
+
+ private static Class<?> getCustomizerClass(final Object handler) {
+ try {
+ final Set<Field> customizerFields =
+ ReflectionUtils.getAllFields(handler.getClass(), field -> "customizer".equals(field.getName()));
+ final Field customizerField = customizerFields.iterator().next();
+ customizerField.setAccessible(true);
+ return customizerField.get(handler).getClass();
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(format("Unable to get customizer from %s ", handler), e);
+ }
+ }
+
+ private static Set<WriterFactory> getInjectedWriterFactories(final List<Module> scannedModules) {
+ Injector injector = Guice.createInjector(scannedModules);
+ TypeLiteral<Set<WriterFactory>> writerFactoryType = new TypeLiteral<Set<WriterFactory>>() {
+ };
+ return injector.getInstance(Key.get(writerFactoryType));
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageScanner.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageScanner.java
new file mode 100644
index 000000000..c1c67d77b
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageScanner.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+
+import static java.lang.String.format;
+
+import io.fd.hc2vpp.docs.api.Operation;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.objectweb.asm.ClassReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Scans provided class for reference under specified crud method
+ */
+public class CoverageScanner {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CoverageScanner.class);
+
+ private final Class<?> classToScan;
+ private final Operation.CrudOperation crudOperation;
+ private final Class<?> referenceClass;
+
+ public CoverageScanner(final Class<?> classToScan,
+ final Operation.CrudOperation crudOperation,
+ final Class<?> referenceClass) {
+ this.classToScan = classToScan;
+ this.crudOperation = crudOperation;
+ this.referenceClass = referenceClass;
+ }
+
+ static ClassReader loadClass(String className) {
+ try (InputStream classStream =
+ CoverageScanner.class.getClassLoader().getResourceAsStream(className + ".class")) {
+ return new ClassReader(classStream);
+ } catch (IOException e) {
+ throw new IllegalStateException(format("Unable to load bytecode for class %s", className), e);
+ }
+ }
+
+ public Set<PluginMethodReference> scan() {
+ LOG.debug("Scanning class {}", classToScan.getName());
+ final ClassReader classReader = loadClass(byteCodeStyleReference(classToScan.getName()));
+ final Set<PluginMethodReference> foundReferences = Collections.synchronizedSet(new HashSet<>());
+ classReader.accept(new MethodDelegatingClassVisitor(byteCodeStyleReference(classToScan.getName()),
+ crudOperation.getMethodReference(), byteCodeStyleReference(referenceClass.getPackage().getName()),
+ foundReferences, null), ClassReader.SKIP_DEBUG);
+ return foundReferences;
+ }
+
+ // converts java style reference to bytecode-style name(with slashes instead of dots)
+ private static String byteCodeStyleReference(final String javaStyleName) {
+ return javaStyleName.replace(".", "/");
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/LinkGenerator.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/LinkGenerator.java
new file mode 100644
index 000000000..3226639b1
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/LinkGenerator.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+public interface LinkGenerator {
+
+ static String resolveBranch(final String version) {
+ if (version.contains("SNAPSHOT")) {
+ return "master";
+ } else {
+ return "stable%2F" + version.replace(".", "");
+ }
+ }
+
+ default String generateLink(final String raw, final String version) {
+ //https://git.fd.io/hc2vpp/tree/interface-role/api/src/main/yang/interface-role@2017-06-15.yang?h=stable%2F1707
+ return "https://git.fd.io/hc2vpp/tree" + raw + "?h=" + resolveBranch(version);
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodDelegatingClassVisitor.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodDelegatingClassVisitor.java
new file mode 100644
index 000000000..39a06e626
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodDelegatingClassVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+
+import java.util.Set;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class MethodDelegatingClassVisitor extends ClassVisitor {
+
+ private final String currentClass;
+ private final String methodName;
+ private final String reference;
+ private final Set<PluginMethodReference> foundReferences;
+ private final Set<String> allreadyProcessedLocalMethods;
+
+ public MethodDelegatingClassVisitor(String currentClass,
+ String methodName,
+ String reference,
+ Set<PluginMethodReference> foundReferences,
+ Set<String> allreadyProcessedLocalMethods) {
+ super(Opcodes.ASM5);
+ this.currentClass = currentClass;
+ this.methodName = methodName;
+ this.reference = reference;
+ this.foundReferences = foundReferences;
+ this.allreadyProcessedLocalMethods = allreadyProcessedLocalMethods;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if (name.equals(methodName)) {
+ return new MethodPluginCoverageVisitor(currentClass, foundReferences, reference,
+ allreadyProcessedLocalMethods);
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodPluginCoverageVisitor.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodPluginCoverageVisitor.java
new file mode 100644
index 000000000..fe15f5e79
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/MethodPluginCoverageVisitor.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import static java.lang.String.format;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MethodPluginCoverageVisitor extends MethodVisitor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodPluginCoverageVisitor.class);
+
+ private final String currentClass;
+ private final Set<PluginMethodReference> foundReferences;
+ private final String reference;
+ private final Set<String> allreadyProcessedLocal;
+
+ public MethodPluginCoverageVisitor(String currentClass, Set<PluginMethodReference> foundReferences,
+ String reference,
+ Set<String> allreadyProcessedLocal) {
+ super(Opcodes.ASM5);
+ this.currentClass = currentClass;
+ this.foundReferences = foundReferences;
+ this.reference = reference;
+ // if nonnull then reuse
+ this.allreadyProcessedLocal = allreadyProcessedLocal == null
+ ? new HashSet<>()
+ : allreadyProcessedLocal;
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
+ final String normalizedOwner = owner.replace(";", "").replace("[L", "");
+ if (normalizedOwner.contains(reference)) {
+ // reference was found directly in method code
+ foundReferences.add(new PluginMethodReference(currentClass, owner, name));
+ } else {
+ if (normalizedOwner.contains("io/fd")) {
+ // filter just our method to reduce scope
+ if (!normalizedOwner.equals(currentClass)) {
+ LOG.debug("Processing non-current {}.{}()", normalizedOwner, name);
+ // method call is from different class than currently processed one
+ ClassReader classReader = CoverageScanner.loadClass(normalizedOwner);
+ classReader.accept(new MethodDelegatingClassVisitor(normalizedOwner, name, reference,
+ foundReferences,
+ allreadyProcessedLocal), ClassReader.SKIP_DEBUG);
+ } else {
+ LOG.debug("Processing current {}.{}()", normalizedOwner, name);
+ // other methods in same class that are used in visited method
+ String fullyQualifiedMethodName = fullyQualifiedMethodName(normalizedOwner, name, desc);
+ if (allreadyProcessedLocal.contains(fullyQualifiedMethodName)) {
+ //skip already processed local methods to prevent stack overflow
+ return;
+ }
+ allreadyProcessedLocal.add(fullyQualifiedMethodName);
+
+ ClassReader classReader = CoverageScanner.loadClass(normalizedOwner);
+ classReader.accept(new MethodDelegatingClassVisitor(normalizedOwner, name, reference,
+ foundReferences,
+ allreadyProcessedLocal), ClassReader.SKIP_DEBUG);
+ }
+ }
+ }
+ super.visitMethodInsn(opcode, owner, name, desc, isInterface);
+ }
+
+ private String fullyQualifiedMethodName(String owner, String name, String desc) {
+ return format("%s_%s_%s", owner, name, desc);
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelLinkIndex.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelLinkIndex.java
new file mode 100644
index 000000000..c1b299826
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelLinkIndex.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Index from module file name to git generateLink
+ */
+class ModelLinkIndex implements LinkGenerator {
+
+ private final Map<String, String> modelLinkIndex;
+
+ /**
+ * @param projectRoot for ex.: /home/jsrnicek/Projects/hc2vpp
+ * @param version for ex.: 17.07 to get generateLink for correct branch
+ */
+ ModelLinkIndex(final String projectRoot, final String version) {
+ modelLinkIndex = buildIndex(projectRoot, version);
+ }
+
+ private static String key(String raw) {
+ return raw.substring(raw.lastIndexOf("/"))
+ .replace("/", "")
+ .replace(".yang", "");
+ }
+
+ String linkForModel(final String model, final String revision) {
+ // TODO - figure out how to get revision for model in src,to use YangModelKey
+ // if not local model,add generateLink to ietf datatracker
+ return Optional.ofNullable(modelLinkIndex.get(model + "@" + revision))
+ .orElse(Optional.ofNullable(modelLinkIndex.get(model))
+ .orElse("https://datatracker.ietf.org/"));
+ }
+
+ private Map<String, String> buildIndex(final String projectRoot, final String version) {
+ try {
+ return Files.walk(Paths.get(projectRoot))
+ .filter(path -> path.toString().contains("src/main/yang"))
+ .filter(path -> path.toString().endsWith(".yang"))
+ .map(Path::toString)
+ .map(s -> s.replace(projectRoot, ""))
+ .distinct()
+ .collect(Collectors.toMap(ModelLinkIndex::key, o -> generateLink(o, version)));
+ } catch (IOException e) {
+ throw new IllegalStateException(format("%s not found", projectRoot), e);
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelTypeIndex.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelTypeIndex.java
new file mode 100644
index 000000000..9fd5976b7
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/ModelTypeIndex.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import static java.util.stream.Collectors.toMap;
+
+import com.google.common.io.Resources;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+
+/**
+ * Maps namespaces to models
+ */
+class ModelTypeIndex {
+
+ private final Map<YangModelKey, String> namespaceToModuleIndex;
+
+ ModelTypeIndex() throws IOException {
+ namespaceToModuleIndex = collectAllModules(this.getClass().getClassLoader())
+ .stream()
+ .collect(toMap(YangModelKey::new, YangModuleInfo::getName));
+ }
+
+ private static YangModelBindingProvider getModuleBindingProviderInstance(final Class<?> aClass) {
+ try {
+ return (YangModelBindingProvider) aClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static Class<?> loadClass(final ClassLoader classLoader, final String name) {
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+
+ }
+ }
+
+ private static List<String> loadResource(final URL url) {
+ try {
+ return Resources.readLines(url, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ String namespaceToModule(final String namespace,
+ final String revision) {
+ return namespaceToModuleIndex.get(new YangModelKey(namespace, revision));
+ }
+
+ private Set<YangModuleInfo> collectAllModules(final ClassLoader classLoader) throws IOException {
+ return Collections.list(classLoader.getResources("META-INF/services/" +
+ YangModelBindingProvider.class.getName()))
+ .stream()
+ .map(ModelTypeIndex::loadResource)
+ .flatMap(Collection::stream)
+ .map(name -> loadClass(classLoader, name))
+ .map(ModelTypeIndex::getModuleBindingProviderInstance)
+ .map(YangModelBindingProvider::getModuleInfo)
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/PluginMethodReference.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/PluginMethodReference.java
new file mode 100644
index 000000000..5a98639ae
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/PluginMethodReference.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+/**
+ * Represent found reference of plugin method
+ */
+public class PluginMethodReference {
+
+ /**
+ * Name of the class that uses such reference
+ */
+ private final String caller;
+
+ /**
+ * Class of the reference
+ */
+ private final String owner;
+
+ /**
+ * Name of the reference
+ */
+ private final String name;
+
+ public PluginMethodReference(final String caller, final String owner, final String name) {
+ this.caller = caller;
+ this.owner = owner;
+ this.name = name;
+ }
+
+ public String getCaller() {
+ return caller;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/VppApiUtils.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/VppApiUtils.java
new file mode 100644
index 000000000..f21cc2660
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/VppApiUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import com.google.common.base.CaseFormat;
+import io.fd.hc2vpp.docs.api.VppApiMessage;
+
+
+public interface VppApiUtils {
+
+ static String vppApiFromJavaApi(final String jvppApi) {
+ return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, jvppApi);
+ }
+
+ static String generateVppApiDocLink(final String version, final String vppApi) {
+ //https://docs.fd.io/vpp/17.07/d9/d1d/structvl__api__create__subif__t.html
+ // links are using double underscore
+ //final String doubleUnderscoreApiName = vppApi.replace("_", "__");
+ //return format("https://docs.fd.io/vpp/%s/d9/d1d/structvl__api__%s__t.html", version, doubleUnderscoreApiName);
+
+ // FIXME - generateLink has dynamic part that can be resolved from api name
+ return "https://docs.fd.io/vpp/17.07/annotated.html";
+ }
+
+ default VppApiMessage fromJvppApi(final String version, final PluginMethodReference jvppApi) {
+ final String vppApi = vppApiFromJavaApi(jvppApi.getName());
+ return new VppApiMessage(vppApi, generateVppApiDocLink(version, vppApi));
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangModelKey.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangModelKey.java
new file mode 100644
index 000000000..2bc5bc5da
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangModelKey.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+
+final class YangModelKey {
+ private final String namespace;
+ private final String revision;
+
+ YangModelKey(final YangModuleInfo moduleInfo) {
+ this.namespace = moduleInfo.getNamespace();
+ this.revision = moduleInfo.getRevision();
+ }
+
+ YangModelKey(final String namespace, final String revision) {
+ this.namespace = namespace;
+ this.revision = revision;
+ }
+
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public String getRevision() {
+ return revision;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final YangModelKey that = (YangModelKey) o;
+
+ if (namespace != null
+ ? !namespace.equals(that.namespace)
+ : that.namespace != null) {
+ return false;
+ }
+ return revision != null
+ ? revision.equals(that.revision)
+ : that.revision == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = namespace != null
+ ? namespace.hashCode()
+ : 0;
+ result = 31 * result + (revision != null
+ ? revision.hashCode()
+ : 0);
+ return result;
+ }
+}
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangTypeLinkIndex.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangTypeLinkIndex.java
new file mode 100644
index 000000000..8220d7f78
--- /dev/null
+++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/YangTypeLinkIndex.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class YangTypeLinkIndex {
+
+ private final ModelLinkIndex modelLinkIndex;
+ private final ModelTypeIndex modelTypeIndex;
+
+ public YangTypeLinkIndex(final String projectRoot, final String version) {
+ modelLinkIndex = new ModelLinkIndex(projectRoot, version);
+ try {
+ modelTypeIndex = new ModelTypeIndex();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public String getLinkForType(final String classname) {
+ final Class<?> loadedClass;
+ final QName qname;
+ try {
+ loadedClass = this.getClass().getClassLoader().loadClass(classname);
+ final Field qnameField = loadedClass.getField("QNAME");
+ qname = QName.class.cast(qnameField.get(null));
+ } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
+ throw new IllegalStateException(format("Unable to extract QNAME from %s", classname), e);
+ }
+
+
+ final String namespace = qname.getNamespace().toString();
+ final String formattedRevision = qname.getFormattedRevision();
+ final String model = modelTypeIndex.namespaceToModule(namespace, formattedRevision);
+ return modelLinkIndex.linkForModel(model, formattedRevision);
+ }
+}
diff --git a/vpp-integration/api-docs/docs/pom.xml b/vpp-integration/api-docs/docs/pom.xml
new file mode 100644
index 000000000..cdd3cf463
--- /dev/null
+++ b/vpp-integration/api-docs/docs/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<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>
+
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>docs</artifactId>
+ <version>1.17.10-SNAPSHOT</version>
+
+ <properties>
+ <!-- List of modules that are used to extract Writer/Reader factories, and therefore generate api documentation -->
+ <api.docs.modules>
+ io.fd.hc2vpp.docs.core.mock.binding.MockBindingModule,
+ io.fd.hc2vpp.docs.core.mock.binding.MockAclModule,
+ io.fd.hc2vpp.docs.core.mock.binding.MockNshModule,
+ io.fd.hc2vpp.docs.core.mock.binding.MockIoamModule,
+ io.fd.hc2vpp.docs.core.mock.binding.MockNatModule,
+ io.fd.hc2vpp.iface.role.InterfaceRoleModule,
+ io.fd.hc2vpp.l3.InterfaceL3Module,
+ io.fd.hc2vpp.l3.ProxyArpModule,
+ io.fd.hc2vpp.l3.SubInterfaceL3Module,
+ io.fd.hc2vpp.lisp.LispModule,
+ io.fd.hc2vpp.lisp.gpe.GpeModule,
+ io.fd.hc2vpp.management.VppManagementModule,
+ io.fd.hc2vpp.policer.PolicerModule,
+ io.fd.hc2vpp.routing.RoutingModule,
+ io.fd.hc2vpp.v3po.V3poModule,
+ io.fd.hc2vpp.vpp.classifier.InterfaceClassifierAclModule,
+ io.fd.hc2vpp.vpp.classifier.SubInterfaceClassifierAclModule,
+ io.fd.hc2vpp.vpp.classifier.VppClassifierModule,
+ io.fd.hc2vpp.dhcp.DhcpModule,
+ io.fd.hc2vpp.bgp.inet.BgpInetModule
+ </api.docs.modules>
+ <project.root.folder>${project.basedir}/../../..</project.root.folder>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.gmaven</groupId>
+ <artifactId>groovy-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-coverage-doc</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <configuration>
+ <source>
+ io.fd.hc2vpp.docs.scripts.ApiDocsIndexGenerator.generate(project, log)
+ </source>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>scripts</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+</project> \ No newline at end of file
diff --git a/vpp-integration/api-docs/pom.xml b/vpp-integration/api-docs/pom.xml
new file mode 100644
index 000000000..cb1f1ac61
--- /dev/null
+++ b/vpp-integration/api-docs/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<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">
+ <parent>
+ <artifactId>hc2vpp-parent</artifactId>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <version>1.17.10-SNAPSHOT</version>
+ <relativePath>../../common/hc2vpp-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>api-docs</artifactId>
+ <packaging>pom</packaging>
+ <version>1.17.10-SNAPSHOT</version>
+
+ <modules>
+ <module>core</module>
+ <module>api</module>
+ <module>docs</module>
+ <module>scripts</module>
+ </modules>
+</project> \ No newline at end of file
diff --git a/vpp-integration/api-docs/scripts/pom.xml b/vpp-integration/api-docs/scripts/pom.xml
new file mode 100644
index 000000000..f7b14ff62
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/pom.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 Cisco and/or its affiliates.
+ ~
+ ~ 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.
+ -->
+
+<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>
+
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>scripts</artifactId>
+ <version>1.17.10-SNAPSHOT</version>
+
+ <properties>
+ <groovy.version>2.4.7</groovy.version>
+ <groovy.eclipse.compiler.version>2.9.2-01</groovy.eclipse.compiler.version>
+ <groovy.eclipse.batch.version>2.4.3-01</groovy.eclipse.batch.version>
+
+ <jvpp.version>17.10-SNAPSHOT</jvpp.version>
+ <junit.version>4.12</junit.version>
+ <reflections.version>0.9.11</reflections.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.fd.hc2vpp.docs</groupId>
+ <artifactId>docs-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <version>${groovy.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-registry</artifactId>
+ <version>${jvpp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-core</artifactId>
+ <version>${jvpp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>${reflections.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.hc2vpp.acl</groupId>
+ <artifactId>acl-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.nat</groupId>
+ <artifactId>nat2vpp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.ioam</groupId>
+ <artifactId>vppioam-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.nsh</groupId>
+ <artifactId>vppnsh-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.v3po</groupId>
+ <artifactId>v3po2vpp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.lisp</groupId>
+ <artifactId>lisp2vpp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.management</groupId>
+ <artifactId>vpp-management-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.iface.role</groupId>
+ <artifactId>impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.l3</groupId>
+ <artifactId>l3-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.vpp.classifier</groupId>
+ <artifactId>vpp-classifier-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.routing</groupId>
+ <artifactId>routing-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.dhcp</groupId>
+ <artifactId>dhcp-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.bgp</groupId>
+ <artifactId>bgp-inet</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- Extract plugins and resources from them -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <!-- Dependencies are copied by parent project -->
+ <execution>
+ <id>unpack-configuration</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includes>**/honeycomb-minimal-resources/</includes>
+ <outputDirectory>${project.build.outputDirectory}/</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-eclipse-compiler</artifactId>
+ <version>${groovy.eclipse.compiler.version}</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
+ <configuration>
+ <compilerId>groovy-eclipse-compiler</compilerId>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-eclipse-compiler</artifactId>
+ <version>${groovy.eclipse.compiler.version}</version>
+ </dependency>
+ <!-- for 2.8.0-01 and later you must have an explicit dependency on groovy-eclipse-batch -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-eclipse-batch</artifactId>
+ <version>${groovy.eclipse.batch.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project> \ No newline at end of file
diff --git a/vpp-integration/api-docs/scripts/src/main/groovy/io/fd/hc2vpp/docs/scripts/ApiDocsIndexGenerator.groovy b/vpp-integration/api-docs/scripts/src/main/groovy/io/fd/hc2vpp/docs/scripts/ApiDocsIndexGenerator.groovy
new file mode 100644
index 000000000..238f4a25b
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/groovy/io/fd/hc2vpp/docs/scripts/ApiDocsIndexGenerator.groovy
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.scripts
+
+import groovy.text.SimpleTemplateEngine
+import io.fd.hc2vpp.docs.api.*
+import io.fd.hc2vpp.docs.core.ClassPathTypeIndex
+import io.fd.hc2vpp.docs.core.CoverageGenerator
+import io.fd.hc2vpp.docs.core.YangTypeLinkIndex
+import io.fd.vpp.jvpp.acl.future.FutureJVppAcl
+import io.fd.vpp.jvpp.core.future.FutureJVppCore
+import io.fd.vpp.jvpp.ioamexport.future.FutureJVppIoamexport
+import io.fd.vpp.jvpp.ioampot.future.FutureJVppIoampot
+import io.fd.vpp.jvpp.ioamtrace.future.FutureJVppIoamtrace
+import io.fd.vpp.jvpp.nsh.future.FutureJVppNsh
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnat
+
+import java.nio.charset.StandardCharsets
+import java.nio.file.Files
+import java.nio.file.Paths
+import java.nio.file.StandardOpenOption
+import java.util.stream.Collectors
+
+import static java.util.stream.Collectors.toList
+
+/**
+ * Generates VPP api to Yang node index for hc2vpp guice modules listed in api.docs.modules maven property.
+ */
+class ApiDocsIndexGenerator {
+
+ private static def NL = System.lineSeparator()
+ // TODO - check if list of plugin classes can be generated based on list of modules enabled for doc generation
+ private static
+ def PLUGIN_CLASSES = [FutureJVppCore.class, FutureJVppAcl.class, FutureJVppSnat.class, FutureJVppNsh.class,
+ FutureJVppIoamexport.class, FutureJVppIoampot.class, FutureJVppIoamtrace.class]
+ private static def TABLE_PART_MARK = "|"
+
+ /**
+ * Generate coverage data for all configured coverage.modules and JVpp plugins
+ * */
+ public static void generate(final project, final log) {
+ def loader = this.getClassLoader()
+
+ String moduleNames = project.properties.get("api.docs.modules")
+ String projectRoot = project.properties.get("project.root.folder")
+
+ if (moduleNames.trim().isEmpty()) {
+ log.info "No modules defined for ${project.name}. Skipping api-docs generation."
+ return
+ }
+
+ final List<String> moduleNamesList = moduleNames.split(",")
+
+ log.info "Reading module list for ${project.name}"
+ def modules = moduleNamesList.stream()
+ .map { moduleName -> moduleName.trim() }
+ .map { moduleName ->
+ log.info "Loading class $moduleName"
+ loader.loadClass(moduleName).newInstance()
+ }
+ .collect(toList())
+
+ String outPath = project.build.outputDirectory
+
+ log.info "Generating yang type generateLink index"
+ YangTypeLinkIndex yangTypeIndex = new YangTypeLinkIndex(projectRoot, project.version)
+ log.info "Classpath type generateLink index"
+ ClassPathTypeIndex classPathIndex = new ClassPathTypeIndex(projectRoot, project.version)
+
+ log.info "Generating VPP API to YANG mapping"
+ PLUGIN_CLASSES.stream()
+ .forEach { pluginClass ->
+ log.info "Generating mapping for ${pluginClass}"
+ final PluginCoverage configCoverage = new CoverageGenerator()
+ .generateConfigCoverage(pluginClass, project.version, modules, yangTypeIndex, classPathIndex)
+ generateJvppCoverageDoc(configCoverage, outPath, log)
+
+ //TODO operational coverage
+ }
+ }
+
+ static void generateJvppCoverageDoc(
+ final PluginCoverage pluginCoverage, final String outPath, final log) {
+ if (!pluginCoverage.hasCoverage()) {
+ log.info "Plugin ${pluginCoverage.getPluginName()} does not have coverage data, skipping config docs generation"
+ return
+ }
+ log.info "Generating config api docs for plugin ${pluginCoverage.getPluginName()}"
+ def template = this.getClassLoader().getResource("yang_to_jvpp_template")
+ def result = new SimpleTemplateEngine()
+ .createTemplate(template)
+ .make(["pluginName": pluginCoverage.getPluginName(), "tableContent": generateConfigTableContent(pluginCoverage.getCoverage())]).toString()
+
+ log.debug "Docs result for ${pluginCoverage.getPluginName()}$NL$result"
+
+ Paths.get(outPath).toFile().mkdirs()
+
+ def outFileName
+ if (pluginCoverage.isConfig()) {
+ outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-config-index.adoc"
+ } else {
+ outFileName = "${normalizePluginName(pluginCoverage.getPluginName())}-yang-operational-index.adoc"
+ }
+
+ def outFilePath = Paths.get(outPath, outFileName)
+
+ Files.write(outFilePath, result.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE)
+ log.info "Plugin ${pluginCoverage.getPluginName()} config api docs sucessfully writen to ${outFilePath.toString()}"
+ }
+
+ private static String generateConfigTableContent(final Set<CoverageUnit> coverage) {
+ coverage.stream()
+ .map { unit ->
+ "$NL" +
+ "${vppApiWithLink(unit.vppApi)}" +
+ "${javaApi(unit.javaApi)}" +
+ "${yangTypes(unit.yangTypes)}" +
+ "${supportedOperations(unit.supportedOperations)}"
+ }
+ .collect(Collectors.joining(NL))
+ }
+
+ private static String vppApiWithLink(final VppApiMessage vppApi) {
+ "$TABLE_PART_MARK${vppApi.link}[${vppApi.name}]$NL"
+ }
+
+ private static String javaApi(final JavaApiMessage javaApi) {
+ "$TABLE_PART_MARK${javaApi.api}$NL"
+ }
+
+ private static String yangTypes(final List<YangType> yangTypes) {
+ "$NL$TABLE_PART_MARK$NL ${yangTypes.stream().map { yangType -> " ${yangType.link}[${yangType.type}]" }.collect(Collectors.joining(NL))}"
+ }
+
+ private static String supportedOperations(final List<Operation> operations) {
+ "$NL$TABLE_PART_MARK${operations.stream().map { reference -> " ${reference.link}[${reference.operation}]" }.collect(Collectors.joining(NL))}"
+ }
+
+ private static String normalizePluginName(final String name) {
+ name.toLowerCase().replace(" ", "-")
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockAclModule.java b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockAclModule.java
new file mode 100644
index 000000000..436061850
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockAclModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core.mock.binding;
+
+import static io.fd.hc2vpp.docs.core.mock.binding.MockBindingModule.noOpProxy;
+
+import com.google.inject.Provider;
+import io.fd.hc2vpp.acl.AclModule;
+import io.fd.vpp.jvpp.JVpp;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade;
+import java.io.IOException;
+
+/**
+ * Use to bypass jvpp registration
+ */
+public class MockAclModule extends AclModule {
+
+ public MockAclModule() {
+ super(MockFutureAclProvider.class);
+ }
+
+ static class MockFutureAclProvider implements Provider<FutureJVppAclFacade> {
+
+ @Override
+ public FutureJVppAclFacade get() {
+ try {
+ return new FutureJVppAclFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockBindingModule.java b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockBindingModule.java
new file mode 100644
index 000000000..e6500ea4c
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockBindingModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core.mock.binding;
+
+import static com.google.inject.name.Names.named;
+
+import com.google.inject.AbstractModule;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+
+/**
+ * Use to bypass jvpp registration, and infra modules
+ */
+public class MockBindingModule extends AbstractModule {
+
+ private static final InvocationHandler NOOP_INVOCATION_HANDLER = (proxy, method, args) -> null;
+
+ @Override
+ protected void configure() {
+ bind(FutureJVppCore.class).toInstance(noOpProxy(FutureJVppCore.class));
+ bind(MappingContext.class).annotatedWith(named("honeycomb-context"))
+ .toInstance(noOpProxy(MappingContext.class));
+ bind(DataBroker.class).annotatedWith(named("honeycomb-context")).toInstance(noOpProxy(DataBroker.class));
+ bind(JVppRegistry.class).toInstance(noOpProxy(JVppRegistry.class));
+ }
+
+ static <T> T noOpProxy(Class<T> clazz) {
+ return (T) Proxy.newProxyInstance(MockBindingModule.class.getClassLoader(),
+ new Class[]{clazz}, NOOP_INVOCATION_HANDLER);
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockIoamModule.java b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockIoamModule.java
new file mode 100644
index 000000000..f3f06195d
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockIoamModule.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core.mock.binding;
+
+import static io.fd.hc2vpp.docs.core.mock.binding.MockBindingModule.noOpProxy;
+
+import com.google.inject.Provider;
+import io.fd.hc2vpp.vppioam.impl.VppIoamModule;
+import io.fd.vpp.jvpp.JVpp;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.ioamexport.future.FutureJVppIoamexportFacade;
+import io.fd.vpp.jvpp.ioampot.future.FutureJVppIoampotFacade;
+import io.fd.vpp.jvpp.ioamtrace.future.FutureJVppIoamtraceFacade;
+import java.io.IOException;
+
+/**
+ * Use to bypass jvpp registration
+ */
+public class MockIoamModule extends VppIoamModule {
+
+ public MockIoamModule() {
+ super(MockTraceProvider.class, MockPotProvider.class, MockExportProvider.class);
+ }
+
+ private static class MockTraceProvider implements Provider<FutureJVppIoamtraceFacade> {
+ @Override
+ public FutureJVppIoamtraceFacade get() {
+ try {
+ return new FutureJVppIoamtraceFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ private static class MockPotProvider implements Provider<FutureJVppIoampotFacade> {
+
+ @Override
+ public FutureJVppIoampotFacade get() {
+ try {
+ return new FutureJVppIoampotFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ private static class MockExportProvider implements Provider<FutureJVppIoamexportFacade> {
+
+ @Override
+ public FutureJVppIoamexportFacade get() {
+ try {
+ return new FutureJVppIoamexportFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNatModule.java b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNatModule.java
new file mode 100644
index 000000000..d74f7f2b9
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNatModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core.mock.binding;
+
+import static io.fd.hc2vpp.docs.core.mock.binding.MockBindingModule.noOpProxy;
+
+import com.google.inject.Provider;
+import io.fd.hc2vpp.nat.NatModule;
+import io.fd.vpp.jvpp.JVpp;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import java.io.IOException;
+
+/**
+ * Use to bypass jvpp registration
+ */
+public class MockNatModule extends NatModule {
+
+ public MockNatModule() {
+ super(MockJVppSnatProvider.class);
+ }
+
+ private static class MockJVppSnatProvider implements Provider<FutureJVppSnatFacade> {
+
+ @Override
+ public FutureJVppSnatFacade get() {
+ try {
+ return new FutureJVppSnatFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNshModule.java b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNshModule.java
new file mode 100644
index 000000000..dace214e8
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/java/io/fd/hc2vpp/docs/core/mock/binding/MockNshModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * 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 io.fd.hc2vpp.docs.core.mock.binding;
+
+import static io.fd.hc2vpp.docs.core.mock.binding.MockBindingModule.noOpProxy;
+
+import com.google.inject.Provider;
+import io.fd.hc2vpp.vppnsh.impl.VppNshModule;
+import io.fd.vpp.jvpp.JVpp;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.nsh.future.FutureJVppNshFacade;
+import java.io.IOException;
+
+/**
+ * Use to bypass jvpp registration
+ */
+public class MockNshModule extends VppNshModule {
+
+ public MockNshModule() {
+ super(MockJVppNshProvider.class);
+ }
+
+ private static class MockJVppNshProvider implements Provider<FutureJVppNshFacade> {
+
+ @Override
+ public FutureJVppNshFacade get() {
+ try {
+ return new FutureJVppNshFacade(noOpProxy(JVppRegistry.class), noOpProxy(JVpp.class));
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+}
diff --git a/vpp-integration/api-docs/scripts/src/main/resources/routing.json b/vpp-integration/api-docs/scripts/src/main/resources/routing.json
new file mode 100644
index 000000000..95f85414f
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/resources/routing.json
@@ -0,0 +1,4 @@
+{
+ "default-routing-instance-name": "vpp-routing-instance",
+ "learned-route-name-prefix": "learned-route"
+} \ No newline at end of file
diff --git a/vpp-integration/api-docs/scripts/src/main/resources/vpp-management.json b/vpp-integration/api-docs/scripts/src/main/resources/vpp-management.json
new file mode 100644
index 000000000..28b25b263
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/resources/vpp-management.json
@@ -0,0 +1,3 @@
+{
+ "keepalive-delay":30
+} \ No newline at end of file
diff --git a/vpp-integration/api-docs/scripts/src/main/resources/yang_to_jvpp_template b/vpp-integration/api-docs/scripts/src/main/resources/yang_to_jvpp_template
new file mode 100644
index 000000000..cf9502cd5
--- /dev/null
+++ b/vpp-integration/api-docs/scripts/src/main/resources/yang_to_jvpp_template
@@ -0,0 +1,6 @@
+.${pluginName} to Yang index
+[width="80%",options="header",cols="1,1,m,1"]
+|===
+|*VPP api* |*Java api* |*Yang nodes* |*Supported Operations*
+${tableContent}
+|=== \ No newline at end of file
diff --git a/vpp-integration/pom.xml b/vpp-integration/pom.xml
index 5c3da79c8..1bdd655b1 100644
--- a/vpp-integration/pom.xml
+++ b/vpp-integration/pom.xml
@@ -33,6 +33,7 @@
<modules>
<module>minimal-distribution</module>
+ <module>api-docs</module>
</modules>
<!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->