1919package org .apache .accumulo .core .conf ;
2020
2121import static java .nio .charset .StandardCharsets .UTF_8 ;
22+ import static org .apache .accumulo .core .conf .Property .markdownRef ;
2223
2324import java .io .IOException ;
2425import java .io .PrintStream ;
2526import java .util .TreeMap ;
2627
28+ import com .google .gson .Gson ;
29+ import com .google .gson .GsonBuilder ;
30+ import com .google .gson .JsonParser ;
31+
2732/**
2833 * This class generates documentation to inform users of the available configuration properties in a
2934 * presentable form.
3035 */
3136public class ConfigurationDocGen {
3237 private final PrintStream doc ;
3338 private final TreeMap <String ,Property > sortedProps = new TreeMap <>();
39+ private final Gson gsonPrettyPrinter =
40+ new GsonBuilder ().disableJdkUnsafe ().setPrettyPrinting ().create ();
41+
42+ private void generate () {
43+ doc .print ("""
44+ ---
45+ title: Server Properties (4.x)
46+ category: configuration
47+ order: 4
48+ ---
49+
50+ <!--
51+ WARNING: Do not edit this file. It is a generated file that is copied from Accumulo
52+ build (from core/target/generated-docs)
53+ -->
54+
55+ Below are properties set in `accumulo.properties` or the Accumulo shell that configure
56+ Accumulo servers (i.e. tablet server, manager, etc). Properties labeled 'Experimental'
57+ should not be considered stable and have a higher risk of changing in the future.
58+
59+ <table>
60+ <thead>
61+ <tr>
62+ <th>Property</th>
63+ <th>Description</th>
64+ </tr>
65+ </thead>
66+ <tbody>
67+ """ );
3468
35- void generate () {
36- pageHeader ();
37-
38- beginTable ("Property" );
3969 for (Property prop : sortedProps .values ()) {
4070 if (prop .getType () == PropertyType .PREFIX ) {
41- prefixSection (prop );
71+ prefixRow (prop );
4272 } else {
43- property (prop );
73+ propertyRow (prop );
4474 }
4575 }
4676
47- beginSection ( "Property Types" );
48- beginTable ( "Type" );
49- propertyTypeDescriptions ();
77+ doc . println ( """
78+ </tbody>
79+ </table>
5080
51- doc .close ();
52- }
81+ ### Property Types
5382
54- void beginSection (String section ) {
55- doc .println ("\n ### " + section + "\n " );
56- }
83+ <table>
84+ <thead>
85+ <tr>
86+ <th>Type</th>
87+ <th>Description</th>
88+ </tr>
89+ </thead>
90+ <tbody>
91+ """ );
5792
58- void beginTable (String name ) {
59- doc .println ("| " + name + " | Description |" );
60- doc .println ("|--------------|-------------|" );
61- }
93+ for (PropertyType type : PropertyType .values ()) {
94+ if (type != PropertyType .PREFIX ) {
95+ doc .printf ("""
96+ <tr>
97+ <td>%s</td>
98+ <td markdown="1">
6299
63- void pageHeader () {
64- doc .println ("---" );
65- doc .println ("title: Server Properties (4.x)" );
66- doc .println ("category: configuration" );
67- doc .println ("order: 4" );
68- doc .println ("---\n " );
69- doc .println ("<!-- WARNING: Do not edit this file. It is a generated file"
70- + " that is copied from Accumulo build (from core/target/generated-docs) -->\n " );
71- doc .println ("Below are properties set in `accumulo.properties` or the"
72- + " Accumulo shell that configure Accumulo servers (i.e. tablet server,"
73- + " manager, etc). Properties labeled 'Experimental' should not be considered stable"
74- + " and have a higher risk of changing in the future.\n " );
75- }
100+ %s
76101
77- void prefixSection (Property prefix ) {
78- boolean depr = prefix .isDeprecated ();
79- String key = strike ("<a name=\" " + prefix .getKey ().replace ("." , "_" )
80- + "prefix\" class=\" prop\" ></a> **" + prefix .getKey () + "***" , depr );
81- String description = prefix .isExperimental () ? "**Experimental**<br>" : "" ;
82- description += "**Available since:** " + prefix .availableSince () + "<br>" ;
83- if (depr ) {
84- description += "*Deprecated since:* " + prefix .deprecatedSince () + "<br>" ;
85- if (prefix .isReplaced ()) {
86- description += "*Replaced by:* <a href=\" #" + prefix .replacedBy ().getKey ().replace ("." , "_" )
87- + "prefix\" >" + prefix .replacedBy () + "</a><br>" ;
102+ </td>
103+ </tr>
104+ """ , type .toString (), type .getFormatDescription ());
88105 }
89106 }
90- description += strike (sanitize (prefix .getDescription ()), depr );
91- doc .println ("| " + key + " | " + description + " |" );
107+
108+ doc .println ("""
109+ </tbody>
110+ </table>
111+ """ );
112+
113+ doc .close ();
114+ }
115+
116+ private void prefixRow (Property prefix ) {
117+ boolean depr = prefix .isDeprecated ();
118+ doc .printf ("""
119+ <tr>
120+ <td markdown="1"><a name="%sprefix" class="prop"></a>
121+ %s**%s\\ ***%s
122+ </td>
123+ <td markdown="1" style="max-width: 600px">
124+ %s
125+ **Available since:** %s<br>
126+ %s%s
127+
128+ %s
129+
130+ </td>
131+ </tr>
132+ """ , prefix .getKey ().replace ("." , "_" ), depr ? "~~" : "" , prefix .getKey (), depr ? "~~" : "" ,
133+ prefix .isExperimental () ? "**⚠Experimental⚠**<br>" : "" ,
134+ prefix .availableSince (),
135+ depr ? "*Deprecated since:* " + prefix .deprecatedSince () + "<br>" : "" ,
136+ depr && prefix .isReplaced ()
137+ ? "*Replaced by:* %s<br>" .formatted (markdownRef (prefix .replacedBy ().getKey ())) : "" ,
138+ prefix .getDescription ());
92139 }
93140
94- void property (Property prop ) {
141+ private void propertyRow (Property prop ) {
95142 boolean depr = prop .isDeprecated ();
96- String key = strike (
97- "<a name=\" " + prop .getKey ().replace ("." , "_" ) + "\" class=\" prop\" ></a> " + prop .getKey (),
98- depr );
99- String description = prop .isExperimental () ? "**Experimental**<br>" : "" ;
100- description += "**Available since:** " ;
101- if (prop .getKey ().startsWith ("manager." )
102- && (prop .availableSince ().startsWith ("1." ) || prop .availableSince ().startsWith ("2.0" ))) {
103- description += "2.1.0 (formerly *master." + prop .getKey ().substring (8 ) + "* since "
104- + prop .availableSince () + ")<br>" ;
105- } else {
106- description += prop .availableSince () + "<br>" ;
107- }
108- if (depr ) {
109- description += "*Deprecated since:* " + prop .deprecatedSince () + "<br>" ;
110- if (prop .isReplaced ()) {
111- description += "*Replaced by:* <a href=\" #" + prop .replacedBy ().getKey ().replace ("." , "_" )
112- + "\" >" + prop .replacedBy () + "</a><br>" ;
113- }
114- }
115- description += strike (sanitize (prop .getDescription ()), depr ) + "<br>"
116- + strike ("**type:** " + prop .getType ().name (), depr ) + ", "
117- + strike ("**zk mutable:** " + isZooKeeperMutable (prop ), depr ) + ", " ;
118- String defaultValue = sanitize (prop .getDefaultValue ()).trim ();
143+ String del = depr ? "~~" : "" ;
144+ String availableSince = prop .getKey ().startsWith ("manager." )
145+ && (prop .availableSince ().startsWith ("1." ) || prop .availableSince ().startsWith ("2.0" ))
146+ ? "2.1.0 (formerly *master." + prop .getKey ().substring (8 ) + "* since "
147+ + prop .availableSince () + ")"
148+ : prop .availableSince ();
149+ String defaultValue = prop .getDefaultValue ();
119150 if (defaultValue .isEmpty ()) {
120- description += strike ("**default value:** empty" , depr );
121- } else if (defaultValue .contains ("\n " )) {
122- // deal with multi-line values, skip strikethrough of value
123- description += strike ("**default value:** " , depr ) + "\n ```\n " + defaultValue + "\n ```\n " ;
151+ defaultValue = "empty" ;
124152 } else if (prop .getType () == PropertyType .CLASSNAME
125153 && defaultValue .startsWith ("org.apache.accumulo" )) {
126- description += strike ( "**default value:** {% jlink -f " + defaultValue + " %}" , depr ) ;
154+ defaultValue = " {% jlink -f " + defaultValue + " %}" ;
127155 } else {
128- description += strike ("**default value:** `" + defaultValue + "`" , depr );
129- }
130- doc .println ("| " + key + " | " + description + " |" );
131- }
132-
133- private String strike (String s , boolean isDeprecated ) {
134- return (isDeprecated ? "~~" : "" ) + s + (isDeprecated ? "~~" : "" );
135- }
136-
137- void propertyTypeDescriptions () {
138- for (PropertyType type : PropertyType .values ()) {
139- if (type == PropertyType .PREFIX ) {
140- continue ;
141- }
142- doc .println (
143- "| " + sanitize (type .toString ()) + " | " + sanitize (type .getFormatDescription ()) + " |" );
156+ defaultValue = switch (prop .getType ()) {
157+ case JSON , FATE_META_CONFIG , FATE_USER_CONFIG -> """
158+ `%s`
159+
160+ Formatted JSON (for convenience only):
161+ ```json
162+ %s
163+ ```
164+ """ .formatted (defaultValue ,
165+ gsonPrettyPrinter .toJson (JsonParser .parseString (defaultValue )));
166+ default -> "`%s`" .formatted (defaultValue );
167+ };
144168 }
145- }
146-
147- String sanitize (String str ) {
148- return str .replace ("\n " , "<br>" );
169+ doc .printf ("""
170+ <tr>
171+ <td markdown="1"><a name="%s" class="prop"></a>
172+ %s%s%s
173+ </td>
174+ <td markdown="1" style="max-width: 600px">
175+ %s
176+ **Available since:** %s<br>
177+ %s%s
178+
179+ %s
180+
181+ **type:** %s, **zk mutable:** %s, **default value:** %s
182+ </td>
183+ </tr>
184+ """ , prop .getKey ().replace ("." , "_" ), del , prop .getKey (), del ,
185+ prop .isExperimental () ? "**⚠Experimental⚠**<br>" : "" , availableSince ,
186+ depr ? "*Deprecated since:* " + prop .deprecatedSince () + "<br>" : "" ,
187+ depr && prop .isReplaced ()
188+ ? "*Replaced by:* %s<br>" .formatted (markdownRef (prop .replacedBy ().getKey ())) : "" ,
189+ prop .getDescription (), prop .getType ().toString (), isZooKeeperMutable (prop ), defaultValue );
149190 }
150191
151192 private ConfigurationDocGen (PrintStream doc ) {
@@ -160,7 +201,9 @@ private String isZooKeeperMutable(Property prop) {
160201 return "no" ;
161202 }
162203 if (Property .isFixedZooPropertyKey (prop )) {
163- return "yes but requires restart of the " + prop .getKey ().split ("[.]" )[0 ];
204+ String serverName = prop .getKey ().startsWith ("compaction.coordinator." ) ? "manager"
205+ : prop .getKey ().split ("[.]" )[0 ];
206+ return "yes, but requires restart of the " + serverName ;
164207 }
165208 return "yes" ;
166209 }
0 commit comments