Skip to content

Commit

Permalink
[FLINK-17680][docs] Support @ExcludeFromDocumentation when generating…
Browse files Browse the repository at this point in the history
… REST API documentations

This closes apache#12141.
  • Loading branch information
tsreaper authored and tillrohrmann committed May 14, 2020
1 parent 381131a commit f8fe4a4
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,26 @@ public String toString() {
}

/**
* Annotation used on config option fields to exclude the config option from documentation.
* Annotation used on config option fields or options class to mark them as a suffix-option; i.e., a config option
* where the key is only a suffix, with the prefix being danymically provided at runtime.
*/
@Target(ElementType.FIELD)
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Internal
public @interface ExcludeFromDocumentation {
/**
* The optional reason why the config option is excluded from documentation.
*/
String value() default "";
public @interface SuffixOption {
}

/**
* Annotation used on config option fields or options class to mark them as a suffix-option; i.e., a config option
* where the key is only a suffix, with the prefix being danymically provided at runtime.
* Annotation used on config option fields or REST API message headers to exclude it from documentation.
*/
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Internal
public @interface SuffixOption {
public @interface ExcludeFromDocumentation {
/**
* The optional reason why it is excluded from documentation.
*/
String value() default "";
}

private Documentation(){
Expand Down
7 changes: 7 additions & 0 deletions flink-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ under the License.
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-test-utils-junit</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<!-- Used for parsing HTML -->
<groupId>org.jsoup</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package org.apache.flink.docs.rest;

import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.annotation.docs.Documentation;
import org.apache.flink.runtime.rest.RestServerEndpoint;
import org.apache.flink.runtime.rest.handler.async.AsynchronousOperationResult;
import org.apache.flink.runtime.rest.handler.async.AsynchronousOperationStatusMessageHeaders;
Expand Down Expand Up @@ -120,18 +122,24 @@ public static void main(String[] args) throws IOException {
}
}

private static void createHtmlFile(DocumentingRestEndpoint restEndpoint, RestAPIVersion apiVersion, Path outputFile) throws IOException {
@VisibleForTesting
static void createHtmlFile(DocumentingRestEndpoint restEndpoint, RestAPIVersion apiVersion, Path outputFile) throws IOException {
StringBuilder html = new StringBuilder();

List<MessageHeaders> specs = restEndpoint.getSpecs().stream()
.filter(spec -> spec.getSupportedAPIVersions().contains(apiVersion))
.filter(RestAPIDocGenerator::shouldBeDocumented)
.collect(Collectors.toList());
specs.forEach(spec -> html.append(createHtmlEntry(spec)));

Files.deleteIfExists(outputFile);
Files.write(outputFile, html.toString().getBytes(StandardCharsets.UTF_8));
}

private static boolean shouldBeDocumented(MessageHeaders spec) {
return spec.getClass().getAnnotation(Documentation.ExcludeFromDocumentation.class) == null;
}

private static String createHtmlEntry(MessageHeaders<?, ?, ?> spec) {
Class<?> nestedAsyncOperationResultClass = null;
if (spec instanceof AsynchronousOperationStatusMessageHeaders) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.flink.docs.rest;

import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.docs.rest.data.TestEmptyMessageHeaders;
import org.apache.flink.docs.rest.data.TestExcludeMessageHeaders;
import org.apache.flink.runtime.rest.handler.RestHandlerSpecification;
import org.apache.flink.runtime.rest.util.DocumentingRestEndpoint;
import org.apache.flink.runtime.rest.versioning.RestAPIVersion;
import org.apache.flink.util.FileUtils;
import org.apache.flink.util.TestLogger;

import org.apache.flink.shaded.netty4.io.netty.channel.ChannelInboundHandler;

import org.junit.Test;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;

/**
* Tests for the {@link RestAPIDocGenerator}.
*/
public class RestAPIDocGeneratorTest extends TestLogger {

@Test
public void testExcludeFromDocumentation() throws Exception {
File file = File.createTempFile("rest_v0_", ".html");
RestAPIDocGenerator.createHtmlFile(
new TestExcludeDocumentingRestEndpoint(),
RestAPIVersion.V0,
file.toPath());
String actual = FileUtils.readFile(file, "UTF-8");

assertThat(actual, containsString("/test/empty1"));
assertThat(actual, containsString("This is a testing REST API."));
assertThat(actual, containsString("/test/empty2"));
assertThat(actual, containsString("This is another testing REST API."));
assertThat(actual, not(containsString("/test/exclude1")));
assertThat(actual, not(containsString("This REST API should not appear in the generated documentation.")));
assertThat(actual, not(containsString("/test/exclude2")));
assertThat(actual, not(containsString("This REST API should also not appear in the generated documentation.")));
}

private static class TestExcludeDocumentingRestEndpoint implements DocumentingRestEndpoint {

@Override
public List<Tuple2<RestHandlerSpecification, ChannelInboundHandler>> initializeHandlers(CompletableFuture<String> localAddressFuture) {
return Arrays.asList(
Tuple2.of(
new TestEmptyMessageHeaders(
"/test/empty1",
"This is a testing REST API."), null),
Tuple2.of(
new TestEmptyMessageHeaders(
"/test/empty2",
"This is another testing REST API."), null),
Tuple2.of(
new TestExcludeMessageHeaders(
"/test/exclude1",
"This REST API should not appear in the generated documentation."), null),
Tuple2.of(
new TestExcludeMessageHeaders(
"/test/exclude2",
"This REST API should also not appear in the generated documentation."), null));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.flink.docs.rest.data;

import org.apache.flink.runtime.rest.HttpMethodWrapper;
import org.apache.flink.runtime.rest.messages.EmptyMessageParameters;
import org.apache.flink.runtime.rest.messages.EmptyRequestBody;
import org.apache.flink.runtime.rest.messages.EmptyResponseBody;
import org.apache.flink.runtime.rest.messages.MessageHeaders;
import org.apache.flink.runtime.rest.versioning.RestAPIVersion;

import org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpResponseStatus;

import java.util.Collection;
import java.util.Collections;

/**
* A {@link MessageHeaders} for testing purpose.
* Its request body, response body and message parameters are all empty.
*/
public class TestEmptyMessageHeaders implements MessageHeaders<EmptyRequestBody, EmptyResponseBody, EmptyMessageParameters> {

private static final String URL = "/test/empty";
private static final String DESCRIPTION = "This is an empty testing REST API.";

private final String url;
private final String description;

public TestEmptyMessageHeaders() {
this.url = URL;
this.description = DESCRIPTION;
}

public TestEmptyMessageHeaders(String url, String description) {
this.url = url;
this.description = description;
}

@Override
public Class<EmptyRequestBody> getRequestClass() {
return EmptyRequestBody.class;
}

@Override
public Class<EmptyResponseBody> getResponseClass() {
return EmptyResponseBody.class;
}

@Override
public HttpMethodWrapper getHttpMethod() {
return HttpMethodWrapper.GET;
}

@Override
public HttpResponseStatus getResponseStatusCode() {
return HttpResponseStatus.OK;
}

@Override
public String getDescription() {
return description;
}

@Override
public EmptyMessageParameters getUnresolvedMessageParameters() {
return EmptyMessageParameters.getInstance();
}

@Override
public String getTargetRestEndpointURL() {
return url;
}

@Override
public Collection<RestAPIVersion> getSupportedAPIVersions() {
return Collections.singleton(RestAPIVersion.V0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.flink.docs.rest.data;

import org.apache.flink.annotation.docs.Documentation;
import org.apache.flink.runtime.rest.HttpMethodWrapper;
import org.apache.flink.runtime.rest.messages.EmptyMessageParameters;
import org.apache.flink.runtime.rest.messages.EmptyRequestBody;
import org.apache.flink.runtime.rest.messages.EmptyResponseBody;
import org.apache.flink.runtime.rest.messages.MessageHeaders;
import org.apache.flink.runtime.rest.versioning.RestAPIVersion;

import org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpResponseStatus;

import java.util.Collection;
import java.util.Collections;

/**
* A {@link org.apache.flink.runtime.rest.messages.MessageParameter} for testing purpose.
* This REST API should not appear in the generated documentation.
*/
@Documentation.ExcludeFromDocumentation()
public class TestExcludeMessageHeaders implements MessageHeaders<EmptyRequestBody, EmptyResponseBody, EmptyMessageParameters> {

private static final String URL = "/test/excluded";
private static final String DESCRIPTION = "This REST API should not appear in the generated documentation.";

private final String url;
private final String description;

public TestExcludeMessageHeaders() {
this.url = URL;
this.description = DESCRIPTION;
}

public TestExcludeMessageHeaders(String url, String description) {
this.url = URL;
this.description = DESCRIPTION;
}

@Override
public Class<EmptyRequestBody> getRequestClass() {
return EmptyRequestBody.class;
}

@Override
public Class<EmptyResponseBody> getResponseClass() {
return EmptyResponseBody.class;
}

@Override
public HttpMethodWrapper getHttpMethod() {
return HttpMethodWrapper.GET;
}

@Override
public HttpResponseStatus getResponseStatusCode() {
return HttpResponseStatus.OK;
}

@Override
public String getDescription() {
return description;
}

@Override
public EmptyMessageParameters getUnresolvedMessageParameters() {
return EmptyMessageParameters.getInstance();
}

@Override
public String getTargetRestEndpointURL() {
return URL;
}

@Override
public Collection<RestAPIVersion> getSupportedAPIVersions() {
return Collections.singleton(RestAPIVersion.V0);
}
}

0 comments on commit f8fe4a4

Please sign in to comment.