Skip to content

Commit eb9b897

Browse files
authored
Migrate ReferenceDocs resource to plain text (#113866)
Removes the dependency on `XContent` parsing so we can move this out of `:server` and into `:libs:core`.
1 parent a5d033b commit eb9b897

File tree

4 files changed

+233
-176
lines changed

4 files changed

+233
-176
lines changed

server/src/main/java/org/elasticsearch/common/ReferenceDocs.java

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,26 @@
1111

1212
import org.elasticsearch.Build;
1313
import org.elasticsearch.core.SuppressForbidden;
14-
import org.elasticsearch.xcontent.XContentFactory;
15-
import org.elasticsearch.xcontent.XContentParser;
16-
import org.elasticsearch.xcontent.XContentParserConfiguration;
17-
import org.elasticsearch.xcontent.XContentType;
1814

15+
import java.io.BufferedReader;
1916
import java.io.FileNotFoundException;
2017
import java.io.IOException;
2118
import java.io.InputStream;
19+
import java.io.InputStreamReader;
2220
import java.net.URL;
23-
import java.util.LinkedHashMap;
21+
import java.nio.charset.StandardCharsets;
2422
import java.util.Map;
2523
import java.util.regex.Pattern;
2624

2725
/**
2826
* Encapsulates links to pages in the reference docs, so that for example we can include URLs in logs and API outputs. Each instance's
2927
* {@link #toString()} yields (a string representation of) a URL for the relevant docs. Links are defined in the resource file
30-
* {@code reference-docs-links.json} which must include definitions for exactly the set of values of this enum.
28+
* {@code reference-docs-links.txt} which must include definitions for exactly the set of values of this enum.
3129
*/
3230
public enum ReferenceDocs {
3331
/*
34-
* Note that the docs subsystem parses {@code reference-docs-links.json} with regexes, not a JSON parser, so the whitespace in the file
35-
* is important too. See {@code sub check_elasticsearch_links} in {@code https://github.com/elastic/docs/blob/master/build_docs.pl} for
36-
* more details.
32+
* Note that the docs subsystem parses {@code reference-docs-links.txt} differently. See {@code sub check_elasticsearch_links} in
33+
* {@code https://github.com/elastic/docs/blob/master/build_docs.pl} for more details.
3734
*
3835
* Also note that the docs are built from the HEAD of each minor release branch, so in principle docs can move around independently of
3936
* the ES release process. To avoid breaking any links that have been baked into earlier patch releases, you may only add links in a
@@ -89,7 +86,7 @@ public enum ReferenceDocs {
8986
private static final Map<String, String> linksBySymbol;
9087

9188
static {
92-
try (var resourceStream = readFromJarResourceUrl(ReferenceDocs.class.getResource("reference-docs-links.json"))) {
89+
try (var resourceStream = readFromJarResourceUrl(ReferenceDocs.class.getResource("reference-docs-links.txt"))) {
9390
linksBySymbol = Map.copyOf(readLinksBySymbol(resourceStream));
9491
} catch (Exception e) {
9592
assert false : e;
@@ -101,34 +98,69 @@ public enum ReferenceDocs {
10198
static final String CURRENT_VERSION_COMPONENT = "current";
10299
static final String VERSION_COMPONENT = getVersionComponent(Build.current().version(), Build.current().isSnapshot());
103100

104-
static Map<String, String> readLinksBySymbol(InputStream inputStream) throws Exception {
105-
try (var parser = XContentFactory.xContent(XContentType.JSON).createParser(XContentParserConfiguration.EMPTY, inputStream)) {
106-
final var result = parser.map(LinkedHashMap::new, XContentParser::text);
107-
final var iterator = result.keySet().iterator();
108-
for (int i = 0; i < values().length; i++) {
109-
final var expected = values()[i].name();
110-
if (iterator.hasNext() == false) {
111-
throw new IllegalStateException("ran out of values at index " + i + ": expecting " + expected);
112-
}
113-
final var actual = iterator.next();
114-
if (actual.equals(expected) == false) {
115-
throw new IllegalStateException("mismatch at index " + i + ": found " + actual + " but expected " + expected);
116-
}
101+
static final int SYMBOL_COLUMN_WIDTH = 64; // increase as needed to accommodate yet longer symbols
102+
103+
static Map<String, String> readLinksBySymbol(InputStream inputStream) throws IOException {
104+
final var padding = " ".repeat(SYMBOL_COLUMN_WIDTH);
105+
106+
record LinksBySymbolEntry(String symbol, String link) implements Map.Entry<String, String> {
107+
@Override
108+
public String getKey() {
109+
return symbol;
117110
}
118-
if (iterator.hasNext()) {
119-
throw new IllegalStateException("found unexpected extra value: " + iterator.next());
111+
112+
@Override
113+
public String getValue() {
114+
return link;
115+
}
116+
117+
@Override
118+
public String setValue(String value) {
119+
assert false;
120+
throw new UnsupportedOperationException();
120121
}
122+
}
121123

122-
// We must only link to anchors with fixed IDs (defined by [[fragment-name]] in the docs) because auto-generated fragment IDs
123-
// depend on the heading text and are too easy to break inadvertently. Auto-generated fragment IDs begin with an underscore.
124-
for (final var entry : result.entrySet()) {
125-
if (entry.getValue().startsWith("_") || entry.getValue().contains("#_")) {
126-
throw new IllegalStateException("found auto-generated fragment ID at " + entry.getKey());
124+
final var symbolCount = values().length;
125+
final var linksBySymbolEntries = new LinksBySymbolEntry[symbolCount];
126+
127+
try (var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
128+
for (int i = 0; i < symbolCount; i++) {
129+
final var currentLine = reader.readLine();
130+
final var symbol = values()[i].name();
131+
if (currentLine == null) {
132+
throw new IllegalStateException("links resource truncated at line " + (i + 1));
133+
}
134+
if (currentLine.startsWith(symbol + " ") == false) {
135+
throw new IllegalStateException(
136+
"unexpected symbol at line " + (i + 1) + ": expected line starting with [" + symbol + " ]"
137+
);
138+
}
139+
final var link = currentLine.substring(SYMBOL_COLUMN_WIDTH).trim();
140+
if (Strings.hasText(link) == false) {
141+
throw new IllegalStateException("no link found for [" + symbol + "] at line " + (i + 1));
142+
}
143+
final var expectedLine = (symbol + padding).substring(0, SYMBOL_COLUMN_WIDTH) + link;
144+
if (currentLine.equals(expectedLine) == false) {
145+
throw new IllegalStateException("unexpected content at line " + (i + 1) + ": expected [" + expectedLine + "]");
127146
}
147+
148+
// We must only link to anchors with fixed IDs (defined by [[fragment-name]] in the docs) because auto-generated fragment
149+
// IDs depend on the heading text and are too easy to break inadvertently. Auto-generated fragment IDs begin with "_"
150+
if (link.startsWith("_") || link.contains("#_")) {
151+
throw new IllegalStateException(
152+
"found auto-generated fragment ID in link [" + link + "] for [" + symbol + "] at line " + (i + 1)
153+
);
154+
}
155+
linksBySymbolEntries[i] = new LinksBySymbolEntry(symbol, link);
128156
}
129157

130-
return result;
158+
if (reader.readLine() != null) {
159+
throw new IllegalStateException("unexpected trailing content at line " + (symbolCount + 1));
160+
}
131161
}
162+
163+
return Map.ofEntries(linksBySymbolEntries);
132164
}
133165

134166
/**
Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,5 @@
1-
{
2-
"INITIAL_MASTER_NODES": "important-settings.html#initial_master_nodes",
3-
"DISCOVERY_TROUBLESHOOTING": "discovery-troubleshooting.html",
4-
"UNSTABLE_CLUSTER_TROUBLESHOOTING": "troubleshooting-unstable-cluster.html",
5-
"LAGGING_NODE_TROUBLESHOOTING": "troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-lagging",
6-
"SHARD_LOCK_TROUBLESHOOTING": "troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-shardlockobtainfailedexception",
7-
"NETWORK_DISCONNECT_TROUBLESHOOTING": "troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-network",
8-
"CONCURRENT_REPOSITORY_WRITERS": "diagnosing-corrupted-repositories.html",
9-
"ARCHIVE_INDICES": "archive-indices.html",
10-
"HTTP_TRACER": "modules-network.html#http-rest-request-tracer",
11-
"LOGGING": "logging.html",
12-
"BOOTSTRAP_CHECK_HEAP_SIZE": "bootstrap-checks-heap-size.html",
13-
"BOOTSTRAP_CHECK_FILE_DESCRIPTOR": "bootstrap-checks-file-descriptor.html",
14-
"BOOTSTRAP_CHECK_MEMORY_LOCK": "bootstrap-checks-memory-lock.html",
15-
"BOOTSTRAP_CHECK_MAX_NUMBER_THREADS": "max-number-threads-check.html",
16-
"BOOTSTRAP_CHECK_MAX_FILE_SIZE": "bootstrap-checks-max-file-size.html",
17-
"BOOTSTRAP_CHECK_MAX_SIZE_VIRTUAL_MEMORY": "max-size-virtual-memory-check.html",
18-
"BOOTSTRAP_CHECK_MAXIMUM_MAP_COUNT": "bootstrap-checks-max-map-count.html",
19-
"BOOTSTRAP_CHECK_CLIENT_JVM": "bootstrap-checks-client-jvm.html",
20-
"BOOTSTRAP_CHECK_USE_SERIAL_COLLECTOR": "bootstrap-checks-serial-collector.html",
21-
"BOOTSTRAP_CHECK_SYSTEM_CALL_FILTER": "bootstrap-checks-syscall-filter.html",
22-
"BOOTSTRAP_CHECK_ONERROR_AND_ONOUTOFMEMORYERROR": "bootstrap-checks-onerror.html",
23-
"BOOTSTRAP_CHECK_EARLY_ACCESS": "bootstrap-checks-early-access.html",
24-
"BOOTSTRAP_CHECK_ALL_PERMISSION": "bootstrap-checks-all-permission.html",
25-
"BOOTSTRAP_CHECK_DISCOVERY_CONFIGURATION": "bootstrap-checks-discovery-configuration.html",
26-
"BOOTSTRAP_CHECKS": "bootstrap-checks.html",
27-
"BOOTSTRAP_CHECK_ENCRYPT_SENSITIVE_DATA": "bootstrap-checks-xpack.html#bootstrap-checks-xpack-encrypt-sensitive-data",
28-
"BOOTSTRAP_CHECK_PKI_REALM": "bootstrap-checks-xpack.html#bootstrap-checks-xpack-pki-realm",
29-
"BOOTSTRAP_CHECK_ROLE_MAPPINGS": "bootstrap-checks-xpack.html#bootstrap-checks-xpack-role-mappings",
30-
"BOOTSTRAP_CHECK_TLS": "bootstrap-checks-xpack.html#bootstrap-checks-tls",
31-
"BOOTSTRAP_CHECK_TOKEN_SSL": "bootstrap-checks-xpack.html#bootstrap-checks-xpack-token-ssl",
32-
"BOOTSTRAP_CHECK_SECURITY_MINIMAL_SETUP": "security-minimal-setup.html",
33-
"CONTACT_SUPPORT": "troubleshooting.html#troubleshooting-contact-support",
34-
"UNASSIGNED_SHARDS": "red-yellow-cluster-status.html",
35-
"EXECUTABLE_JNA_TMPDIR": "executable-jna-tmpdir.html",
36-
"NETWORK_THREADING_MODEL": "modules-network.html#modules-network-threading-model",
37-
"ALLOCATION_EXPLAIN_API": "cluster-allocation-explain.html",
38-
"NETWORK_BINDING_AND_PUBLISHING": "modules-network.html#modules-network-binding-publishing",
39-
"SNAPSHOT_REPOSITORY_ANALYSIS": "repo-analysis-api.html",
40-
"S3_COMPATIBLE_REPOSITORIES": "repository-s3.html#repository-s3-compatible-services",
41-
"LUCENE_MAX_DOCS_LIMIT": "size-your-shards.html#troubleshooting-max-docs-limit",
42-
"MAX_SHARDS_PER_NODE": "size-your-shards.html#troubleshooting-max-shards-open",
43-
"FLOOD_STAGE_WATERMARK": "fix-watermark-errors.html",
44-
"X_OPAQUE_ID": "api-conventions.html#x-opaque-id",
45-
"FORMING_SINGLE_NODE_CLUSTERS": "modules-discovery-bootstrap-cluster.html#modules-discovery-bootstrap-cluster-joining"
46-
}
1+
[
2+
"Content moved to reference-docs-links.txt",
3+
"This is a temporary placeholder to satisfy sub check_elasticsearch_links in the docs build",
4+
"Remove with @UpdateForV10 (if not before)"
5+
]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
INITIAL_MASTER_NODES important-settings.html#initial_master_nodes
2+
DISCOVERY_TROUBLESHOOTING discovery-troubleshooting.html
3+
UNSTABLE_CLUSTER_TROUBLESHOOTING troubleshooting-unstable-cluster.html
4+
LAGGING_NODE_TROUBLESHOOTING troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-lagging
5+
SHARD_LOCK_TROUBLESHOOTING troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-shardlockobtainfailedexception
6+
NETWORK_DISCONNECT_TROUBLESHOOTING troubleshooting-unstable-cluster.html#troubleshooting-unstable-cluster-network
7+
CONCURRENT_REPOSITORY_WRITERS diagnosing-corrupted-repositories.html
8+
ARCHIVE_INDICES archive-indices.html
9+
HTTP_TRACER modules-network.html#http-rest-request-tracer
10+
LOGGING logging.html
11+
BOOTSTRAP_CHECK_HEAP_SIZE bootstrap-checks-heap-size.html
12+
BOOTSTRAP_CHECK_FILE_DESCRIPTOR bootstrap-checks-file-descriptor.html
13+
BOOTSTRAP_CHECK_MEMORY_LOCK bootstrap-checks-memory-lock.html
14+
BOOTSTRAP_CHECK_MAX_NUMBER_THREADS max-number-threads-check.html
15+
BOOTSTRAP_CHECK_MAX_FILE_SIZE bootstrap-checks-max-file-size.html
16+
BOOTSTRAP_CHECK_MAX_SIZE_VIRTUAL_MEMORY max-size-virtual-memory-check.html
17+
BOOTSTRAP_CHECK_MAXIMUM_MAP_COUNT bootstrap-checks-max-map-count.html
18+
BOOTSTRAP_CHECK_CLIENT_JVM bootstrap-checks-client-jvm.html
19+
BOOTSTRAP_CHECK_USE_SERIAL_COLLECTOR bootstrap-checks-serial-collector.html
20+
BOOTSTRAP_CHECK_SYSTEM_CALL_FILTER bootstrap-checks-syscall-filter.html
21+
BOOTSTRAP_CHECK_ONERROR_AND_ONOUTOFMEMORYERROR bootstrap-checks-onerror.html
22+
BOOTSTRAP_CHECK_EARLY_ACCESS bootstrap-checks-early-access.html
23+
BOOTSTRAP_CHECK_ALL_PERMISSION bootstrap-checks-all-permission.html
24+
BOOTSTRAP_CHECK_DISCOVERY_CONFIGURATION bootstrap-checks-discovery-configuration.html
25+
BOOTSTRAP_CHECKS bootstrap-checks.html
26+
BOOTSTRAP_CHECK_ENCRYPT_SENSITIVE_DATA bootstrap-checks-xpack.html#bootstrap-checks-xpack-encrypt-sensitive-data
27+
BOOTSTRAP_CHECK_PKI_REALM bootstrap-checks-xpack.html#bootstrap-checks-xpack-pki-realm
28+
BOOTSTRAP_CHECK_ROLE_MAPPINGS bootstrap-checks-xpack.html#bootstrap-checks-xpack-role-mappings
29+
BOOTSTRAP_CHECK_TLS bootstrap-checks-xpack.html#bootstrap-checks-tls
30+
BOOTSTRAP_CHECK_TOKEN_SSL bootstrap-checks-xpack.html#bootstrap-checks-xpack-token-ssl
31+
BOOTSTRAP_CHECK_SECURITY_MINIMAL_SETUP security-minimal-setup.html
32+
CONTACT_SUPPORT troubleshooting.html#troubleshooting-contact-support
33+
UNASSIGNED_SHARDS red-yellow-cluster-status.html
34+
EXECUTABLE_JNA_TMPDIR executable-jna-tmpdir.html
35+
NETWORK_THREADING_MODEL modules-network.html#modules-network-threading-model
36+
ALLOCATION_EXPLAIN_API cluster-allocation-explain.html
37+
NETWORK_BINDING_AND_PUBLISHING modules-network.html#modules-network-binding-publishing
38+
SNAPSHOT_REPOSITORY_ANALYSIS repo-analysis-api.html
39+
S3_COMPATIBLE_REPOSITORIES repository-s3.html#repository-s3-compatible-services
40+
LUCENE_MAX_DOCS_LIMIT size-your-shards.html#troubleshooting-max-docs-limit
41+
MAX_SHARDS_PER_NODE size-your-shards.html#troubleshooting-max-shards-open
42+
FLOOD_STAGE_WATERMARK fix-watermark-errors.html
43+
X_OPAQUE_ID api-conventions.html#x-opaque-id
44+
FORMING_SINGLE_NODE_CLUSTERS modules-discovery-bootstrap-cluster.html#modules-discovery-bootstrap-cluster-joining

0 commit comments

Comments
 (0)