2424import java .io .PrintStream ;
2525import java .util .TreeMap ;
2626
27+ import com .google .gson .Gson ;
28+ import com .google .gson .GsonBuilder ;
29+ import com .google .gson .JsonParser ;
30+
2731/**
2832 * This class generates documentation to inform users of the available configuration properties in a
2933 * presentable form.
3034 */
3135public class ConfigurationDocGen {
3236 private final PrintStream doc ;
3337 private final TreeMap <String ,Property > sortedProps = new TreeMap <>();
38+ private final Gson gsonPrettyPrinter =
39+ new GsonBuilder ().disableJdkUnsafe ().setPrettyPrinting ().create ();
40+
41+ private void generate () {
42+ doc .print ("""
43+ ---
44+ title: Server Properties (4.x)
45+ category: configuration
46+ order: 4
47+ ---
48+
49+ <!--
50+ WARNING: Do not edit this file. It is a generated file that is copied from Accumulo
51+ build (from core/target/generated-docs)
52+ -->
53+
54+ Below are properties set in `accumulo.properties` or the Accumulo shell that configure
55+ Accumulo servers (i.e. tablet server, manager, etc). Properties labeled 'Experimental'
56+ should not be considered stable and have a higher risk of changing in the future.
57+
58+ <table>
59+ <thead>
60+ <tr>
61+ <th>Property</th>
62+ <th>Description</th>
63+ </tr>
64+ </thead>
65+ <tbody>
66+ """ );
3467
35- void generate () {
36- pageHeader ();
37-
38- beginTable ("Property" );
3968 for (Property prop : sortedProps .values ()) {
4069 if (prop .getType () == PropertyType .PREFIX ) {
41- prefixSection (prop );
70+ prefixRow (prop );
4271 } else {
43- property (prop );
72+ propertyRow (prop );
4473 }
4574 }
4675
47- beginSection ( "Property Types" );
48- beginTable ( "Type" );
49- propertyTypeDescriptions ();
76+ doc . println ( """
77+ </tbody>
78+ </table>
5079
51- doc .close ();
52- }
80+ ### Property Types
5381
54- void beginSection (String section ) {
55- doc .println ("\n ### " + section + "\n " );
56- }
82+ <table>
83+ <thead>
84+ <tr>
85+ <th>Type</th>
86+ <th>Description</th>
87+ </tr>
88+ </thead>
89+ <tbody>
90+ """ );
5791
58- void beginTable (String name ) {
59- doc .println ("| " + name + " | Description |" );
60- doc .println ("|--------------|-------------|" );
61- }
92+ for (PropertyType type : PropertyType .values ()) {
93+ if (type != PropertyType .PREFIX ) {
94+ doc .printf ("""
95+ <tr>
96+ <td>%s</td>
97+ <td markdown="1">
6298
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- }
99+ %s
76100
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>" ;
101+ </td>
102+ </tr>
103+ """ , type .toString (), type .getFormatDescription ());
88104 }
89105 }
90- description += strike (sanitize (prefix .getDescription ()), depr );
91- doc .println ("| " + key + " | " + description + " |" );
106+
107+ doc .println ("""
108+ </tbody>
109+ </table>
110+ """ );
111+
112+ doc .close ();
113+ }
114+
115+ private void prefixRow (Property prefix ) {
116+ boolean depr = prefix .isDeprecated ();
117+ doc .printf ("""
118+ <tr>
119+ <td markdown="1"><a name="%sprefix" class="prop"></a>
120+ %s**%s\\ ***%s
121+ </td>
122+ <td markdown="1" style="max-width: 600px">
123+ %s
124+ **Available since:** %s<br>
125+ %s%s
126+
127+ %s
128+
129+ </td>
130+ </tr>
131+ """ , prefix .getKey ().replace ("." , "_" ), depr ? "~~" : "" , prefix .getKey (), depr ? "~~" : "" ,
132+ prefix .isExperimental () ? "**⚠Experimental⚠**<br>" : "" ,
133+ prefix .availableSince (),
134+ depr ? "*Deprecated since:* " + prefix .deprecatedSince () + "<br>" : "" ,
135+ depr && prefix .isReplaced () ? """
136+ *Replaced by:* <a href="#%sprefix">%s</a><br>"""
137+ .formatted (prefix .replacedBy ().getKey ().replace ("." , "_" ), prefix .replacedBy ()) : "" ,
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:* <a href="#%s">%s</a><br>"""
189+ .formatted (prop .replacedBy ().getKey ().replace ("." , "_" ), prop .replacedBy ()) : "" ,
190+ prop .getDescription (), prop .getType ().toString (), isZooKeeperMutable (prop ), defaultValue );
149191 }
150192
151193 private ConfigurationDocGen (PrintStream doc ) {
@@ -160,7 +202,9 @@ private String isZooKeeperMutable(Property prop) {
160202 return "no" ;
161203 }
162204 if (Property .isFixedZooPropertyKey (prop )) {
163- return "yes but requires restart of the " + prop .getKey ().split ("[.]" )[0 ];
205+ String serverName = prop .getKey ().startsWith ("compaction.coordinator." ) ? "manager"
206+ : prop .getKey ().split ("[.]" )[0 ];
207+ return "yes, but requires restart of the " + serverName ;
164208 }
165209 return "yes" ;
166210 }
0 commit comments