diff options
author | Jan Srnicek <jsrnicek@cisco.com> | 2017-07-21 15:10:46 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2017-07-25 14:49:21 +0200 |
commit | 69f669f5d16768258f854ce4139033f94ab2afb9 (patch) | |
tree | 4e427e692f0cdaf3e0a412f26279aeef1895fa69 /vpp-integration | |
parent | 25666a0bf99f7b4cf15f14000015014098ddbb6c (diff) |
HC2VPP-180 - Doc coverage generator
TODO - links to specific vpp api section(now points
just to section with apis)
TODO - links to specific java binding code(now
points to class thats doing binding)
TODO - operational coverage(ASM does not support lambda processing)
TODO - generate coverage adoc links
Change-Id: I44c85012da3bd2e7cdd41930753e5aae6955cd7b
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'vpp-integration')
37 files changed, 2466 insertions, 0 deletions
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..44e906f01 --- /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.07-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.07-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..65bc5dc4f --- /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.07-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.07-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..c240ff1e4 --- /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.07-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..d4cc070c0 --- /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.07-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.07-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..c71889408 --- /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.07-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 39ebdd10a..0e57711f6 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 --> |