Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions build-docs.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/bin/bash

# Generate the antora site
./mvnw -pl spring-grpc-docs process-resources antora
# Be sure the ConfigurationPropertiesAsciidocGenerator is compiled
./mvnw -pl spring-grpc-docs package

# Generate the config props and antora site
./mvnw -pl spring-grpc-docs process-resources antora -P docs
7 changes: 7 additions & 0 deletions spring-grpc-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

The top level README and CONTRIBUTING guidelines documentation are generated from sources in this module on `mvn package` using [`asciidoctor-reducer`](https://github.com/asciidoctor/asciidoctor-reducer) and [`downdoc`](https://github.com/opendevise/downdoc).

## Configuration Properties
The Spring gRPC configuration properties are automatically documented as follows:

1. This module contains a Java class (`org.springframework.grpc.internal.ConfigurationPropertiesAsciidocGenerator`) that is compiled when the module is built.
1. This class is then used during the Maven `process-resources` phase in the `docs` profile to generate an asciidoc page containing each of the configuration properties.
1. The asciidoc is then included in the Antora reference documentation.

## Antora Site

To build the Antora site locally run the following command from the project root directory:
Expand Down
50 changes: 50 additions & 0 deletions spring-grpc-docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,23 @@
<maven-exec-plugin.version>3.4.1</maven-exec-plugin.version>
<maven-frontend-plugin.version>1.15.1</maven-frontend-plugin.version>
<maven-gem-plugin.version>3.0.3</maven-gem-plugin.version>
<configprops.path>${project.basedir}/src/main/antora/modules/ROOT/partials/_configprops.adoc</configprops.path>
<configprops.inclusionPattern>spring.grpc.*</configprops.inclusionPattern>
<jruby.version>9.4.6.0</jruby.version>
<disable.checkstyle.checks>true</disable.checkstyle.checks>
</properties>
<!-- Dependencies used to build the config props doc generator -->
<dependencies>
<dependency>
<groupId>org.springframework.grpc</groupId>
<artifactId>spring-grpc-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>rubygems</groupId>
<artifactId>asciidoctor-reducer</artifactId>
Expand Down Expand Up @@ -171,6 +184,43 @@
</plugins>
</build>

<profiles>
<profile>
<id>docs</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${maven-exec-plugin.version}</version>
<executions>
<execution>
<id>generate-configprops</id>
<phase>process-resources</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<includeProjectDependencies>true</includeProjectDependencies>
<includePluginDependencies>false</includePluginDependencies>
<mainClass>
org.springframework.grpc.internal.ConfigurationPropertiesAsciidocGenerator</mainClass>
<arguments>
<argument>${configprops.path}</argument>
<argument>${configprops.inclusionPattern}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<repositories>
<repository>
<id>mavengems</id>
Expand Down
1 change: 1 addition & 0 deletions spring-grpc-docs/src/main/antora/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
* xref:server.adoc[GRPC Server]
* xref:client.adoc[GRPC Clients]
* xref:contribution-guidelines.adoc[Contribution Guidelines]
* xref:appendix.adoc[]
11 changes: 11 additions & 0 deletions spring-grpc-docs/src/main/antora/modules/ROOT/pages/appendix.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
:numbered!:

[appendix]
[[common-application-properties]]
= Common application properties
:page-section-summary-toc: 1

Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches.
This appendix provides a list of common `Spring gRPC` properties.

include::partial$_configprops.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ spring:
----
NOTE: The items in the `health-indicator-paths` are the identifiers of the indicator which is typically the name of the indicator bean without the `HealthIndicator` suffix.

You can use the `spring.grpc.server.health.*` application properties to further configure the health feature.
You can use the xref:appendix.adoc#common-application-properties["spring.grpc.server.health.*"] application properties to further configure the health feature.

== Client-side
Spring gRPC can also autoconfigure the https://grpc.io/docs/guides/health-checking/[client-side] health check feature to your gRPC clients.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
|===
|Name | Default | Description

|spring.grpc.client.channels | | Map of channels configured by name.
|spring.grpc.client.default-channel.address | `+++static://localhost:9090+++` | The target address uri to connect to.
|spring.grpc.client.default-channel.default-deadline | | The default deadline for RPCs performed on this channel.
|spring.grpc.client.default-channel.default-load-balancing-policy | `+++round_robin+++` | The load balancing policy the channel should use.
|spring.grpc.client.default-channel.enable-keep-alive | `+++false+++` | Whether keep alive is enabled on the channel.
|spring.grpc.client.default-channel.health.enabled | `+++false+++` | Whether to enable client-side health check for the channel.
|spring.grpc.client.default-channel.health.service-name | | Name of the service to check health on.
|spring.grpc.client.default-channel.idle-timeout | `+++20s+++` | The duration without ongoing RPCs before going to idle mode.
|spring.grpc.client.default-channel.keep-alive-time | `+++5m+++` | The delay before sending a keepAlive. Note that shorter intervals increase the network burden for the server and this value can not be lower than 'permitKeepAliveTime' on the server.
|spring.grpc.client.default-channel.keep-alive-timeout | `+++20s+++` | The default timeout for a keepAlives ping request.
|spring.grpc.client.default-channel.keep-alive-without-calls | `+++false+++` | Whether a keepAlive will be performed when there are no outstanding RPC on a connection.
|spring.grpc.client.default-channel.max-inbound-message-size | `+++4194304B+++` | Maximum message size allowed to be received by the channel (default 4MiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.max-inbound-metadata-size | `+++8192B+++` | Maximum metadata size allowed to be received by the channel (default 8KiB). Set to '-1' to use the highest possible limit (not recommended).
|spring.grpc.client.default-channel.negotiation-type | `+++plaintext+++` | The negotiation type for the channel.
|spring.grpc.client.default-channel.secure | `+++true+++` | Flag to say that strict SSL checks are not enabled (so the remote certificate could be anonymous).
|spring.grpc.client.default-channel.service-config | | Map representation of the service config to use for the channel.
|spring.grpc.client.default-channel.ssl.bundle | | SSL bundle name.
|spring.grpc.client.default-channel.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
|spring.grpc.client.default-channel.user-agent | | The custom User-Agent for the channel.
|spring.grpc.client.default-stub-factory | | Default stub factory to use for all channels.
|spring.grpc.client.enabled | `+++true+++` | Whether to enable client autoconfiguration.
|spring.grpc.client.inprocess.enabled | `+++true+++` | Whether to configure the in-process channel factory.
|spring.grpc.client.inprocess.exclusive | `+++true+++` | Whether the inprocess channel factory should be the only channel factory available. When the value is true, no other channel factory will be configured.
|spring.grpc.client.observation.enabled | `+++true+++` | Whether to enable Observations on the client.
|spring.grpc.server.address | | The address to bind to in the form 'host:port' or a pseudo URL like 'static://host:port'. When the address is set it takes precedence over any configured host/port values.
|spring.grpc.server.enabled | `+++true+++` | Whether to enable server autoconfiguration.
|spring.grpc.server.exception-handling.enabled | `+++true+++` | Whether to enable user-defined global exception handling on the gRPC server.
|spring.grpc.server.health.actuator.enabled | `+++true+++` | Whether to adapt Actuator health indicators into gRPC health checks.
|spring.grpc.server.health.actuator.health-indicator-paths | | List of Actuator health indicator paths to adapt into gRPC health checks.
|spring.grpc.server.health.actuator.update-initial-delay | `+++5s+++` | The initial delay before updating the health status the very first time.
|spring.grpc.server.health.actuator.update-overall-health | `+++true+++` | Whether to update the overall gRPC server health (the '' service) with the aggregate status of the configured health indicators.
|spring.grpc.server.health.actuator.update-rate | `+++5s+++` | How often to update the health status.
|spring.grpc.server.health.enabled | `+++true+++` | Whether to auto-configure Health feature on the gRPC server.
|spring.grpc.server.host | `+++*+++` | Server host to bind to. The default is any IP address ('*').
|spring.grpc.server.inprocess.exclusive | `+++true+++` | Whether the inprocess server factory should be the only server factory available. When the value is true, no other server factory will be configured.
|spring.grpc.server.inprocess.name | | The name of the in-process server or null to not start the in-process server.
|spring.grpc.server.keep-alive.max-age | | Maximum time a connection may exist before being gracefully terminated (default infinite).
|spring.grpc.server.keep-alive.max-age-grace | | Maximum time for graceful connection termination (default infinite).
|spring.grpc.server.keep-alive.max-idle | | Maximum time a connection can remain idle before being gracefully terminated (default infinite).
|spring.grpc.server.keep-alive.permit-time | `+++5m+++` | Maximum keep-alive time clients are permitted to configure (default 5m).
|spring.grpc.server.keep-alive.permit-without-calls | `+++false+++` | Whether clients are permitted to send keep alive pings when there are no outstanding RPCs on the connection (default false).
|spring.grpc.server.keep-alive.time | `+++2h+++` | Duration without read activity before sending a keep alive ping (default 2h).
|spring.grpc.server.keep-alive.timeout | `+++20s+++` | Maximum time to wait for read activity after sending a keep alive ping. If sender does not receive an acknowledgment within this time, it will close the connection (default 20s).
|spring.grpc.server.max-inbound-message-size | `+++4194304B+++` | Maximum message size allowed to be received by the server (default 4MiB).
|spring.grpc.server.max-inbound-metadata-size | `+++8192B+++` | Maximum metadata size allowed to be received by the server (default 8KiB).
|spring.grpc.server.observation.enabled | `+++true+++` | Whether to enable Observations on the server.
|spring.grpc.server.port | `+++9090+++` | Server port to listen on. When the value is 0, a random available port is selected.
|spring.grpc.server.reflection.enabled | `+++true+++` | Whether to enable Reflection on the gRPC server.
|spring.grpc.server.security.csrf.enabled | `+++false+++` | Whether to enable CSRF protection on gRPC requests.
|spring.grpc.server.servlet.enabled | `+++true+++` | Whether to use a servlet server in a servlet-based web application. When the value is false, a native gRPC server will be created as long as one is available, and it will listen on its own port. Should only be needed if the GrpcServlet is on the classpath
|spring.grpc.server.shutdown-grace-period | `+++30s+++` | Maximum time to wait for the server to gracefully shutdown. When the value is negative, the server waits forever. When the value is 0, the server will force shutdown immediately. The default is 30 seconds.
|spring.grpc.server.ssl.bundle | | SSL bundle name. Should match a bundle configured in spring.ssl.bundle.
|spring.grpc.server.ssl.client-auth | `+++none+++` | Client authentication mode.
|spring.grpc.server.ssl.enabled | | Whether to enable SSL support.
|spring.grpc.server.ssl.secure | `+++true+++` | Flag to indicate that client authentication is secure (i.e. certificates are checked). Do not set this to false in production.

|===
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright 2012-present the original author or authors.
*
* 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
*
* 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.springframework.grpc.internal;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

/**
* Generate Asciidoc for configuration properties.
* <p>
* Copied from 'spring-cloud-build' to avoid direct dependency on Spring Cloud.
*
* @author Marcin Grzejszczak
* @author Chris Bono
*/
public class ConfigurationPropertiesAsciidocGenerator {

public static void main(String... args) {
String outputFile = args[0];
String inclusionPattern = args.length > 1 ? args[1] : ".*";
File parent = new File(outputFile).getParentFile();
if (!parent.exists()) {
System.out.println("No parent directory [" + parent.toString()
+ "] found. Will not generate the configuration properties file");
return;
}
new Generator().generate(outputFile, inclusionPattern);
}

static class Generator {

void generate(String outputFile, String inclusionPattern) {
try {
System.out.println("Parsing all configuration metadata");
Resource[] resources = getResources();
System.out.println("Found [" + resources.length + "] configuration metadata jsons");
TreeSet<String> names = new TreeSet<>();
Map<String, ConfigValue> descriptions = new HashMap<>();
final AtomicInteger count = new AtomicInteger();
final AtomicInteger matchingPropertyCount = new AtomicInteger();
final AtomicInteger propertyCount = new AtomicInteger();
Pattern pattern = Pattern.compile(inclusionPattern);
for (Resource resource : resources) {
if (resourceNameContainsPattern(resource)) {
count.incrementAndGet();
byte[] bytes = StreamUtils.copyToByteArray(resource.getInputStream());
Map<String, Object> response = new ObjectMapper().readValue(bytes, HashMap.class);
List<Map<String, Object>> properties = (List<Map<String, Object>>) response.get("properties");
properties.forEach(val -> {
propertyCount.incrementAndGet();
String name = String.valueOf(val.get("name"));
if (!pattern.matcher(name).matches()) {
return;
}
Object description = val.get("description");
Object defaultValue = val.get("defaultValue");
matchingPropertyCount.incrementAndGet();
names.add(name);
descriptions.put(name, new ConfigValue(name, description, defaultValue));
});
}
}
System.out.println(
"Found [" + count + "] Spring projects configuration metadata jsons. [" + matchingPropertyCount
+ "/" + propertyCount + "] were matching the pattern [" + inclusionPattern + "]");
System.out.println("Successfully built the description table");
if (names.isEmpty()) {
System.out.println("Will not update the table, since no configuration properties were found!");
return;
}
Files.write(new File(outputFile).toPath(), ("|===\n" + "|Name | Default | Description\n\n"
+ names.stream().map(it -> descriptions.get(it).toString()).collect(Collectors.joining("\n"))
+ "\n\n" + "|===")
.getBytes());
System.out.println("Successfully stored the output file");
}
catch (IOException e) {
throw new IllegalStateException(e);
}
}

protected boolean resourceNameContainsPattern(Resource resource) {
try {
return resource.getURL().toString().contains("spring");
}
catch (Exception e) {
System.out.println("Exception [" + e + "] for resource [" + resource
+ "] occurred while trying to retrieve its URL");
return false;
}
}

protected Resource[] getResources() throws IOException {
return new PathMatchingResourcePatternResolver()
.getResources("classpath*:/META-INF/*spring-configuration-metadata.json");
}

}

static class ConfigValue {

public String name;

public String description;

public String defaultValue;

ConfigValue() {
}

ConfigValue(String name, Object description, Object defaultValue) {
this.name = name;
this.description = escapedValue(description);
this.defaultValue = escapedValue(defaultValue);
}

private String escapedValue(Object value) {
return value != null ? value.toString().replaceAll("\\|", "\\\\|") : "";
}

public String toString() {
return "|" + name + " | " + (StringUtils.hasText(defaultValue) ? ("`+++" + defaultValue + "+++`") : "")
+ " | " + description;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"groups": [],
"properties": [
{
"name": "spring.grpc.test.inprocess.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable the in-process server and client for testing. Consider using @AutoConfigInProcessTransport instead.",
"defaultValue": false
}
]
}