1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.site;
21
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.stream.Collectors;
30
31 import org.apache.maven.doxia.macro.AbstractMacro;
32 import org.apache.maven.doxia.macro.Macro;
33 import org.apache.maven.doxia.macro.MacroExecutionException;
34 import org.apache.maven.doxia.macro.MacroRequest;
35 import org.apache.maven.doxia.sink.Sink;
36 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
37 import org.codehaus.plexus.component.annotations.Component;
38
39
40
41
42 @Component(role = Macro.class, hint = "example")
43 public class ExampleMacro extends AbstractMacro {
44
45
46 private static final String XML_CONFIG_START = "/*xml";
47
48
49 private static final String XML_CONFIG_END = "*/";
50
51
52 private static final String CODE_SNIPPET_START = "// xdoc section -- start";
53
54
55 private static final String CODE_SNIPPET_END = "// xdoc section -- end";
56
57
58 private static final String NEWLINE = System.lineSeparator();
59
60
61 private static final String INDENTATION = " ";
62
63
64 private String lastPath = "";
65
66
67 private List<String> lastLines = new ArrayList<>();
68
69 @Override
70 public void execute(Sink sink, MacroRequest request) throws MacroExecutionException {
71 final String path = (String) request.getParameter("path");
72 final String type = (String) request.getParameter("type");
73
74 List<String> lines = lastLines;
75 if (!path.equals(lastPath)) {
76 lines = readFile("src/xdocs-examples/" + path);
77 lastPath = path;
78 lastLines = lines;
79 }
80
81 if ("config".equals(type)) {
82 final String config = getConfigSnippet(lines);
83
84 if (config.isBlank()) {
85 final String message = String.format(Locale.ROOT,
86 "Empty config snippet from %s, check"
87 + " for xml config snippet delimiters in input file.", path
88 );
89 throw new MacroExecutionException(message);
90 }
91
92 writeSnippet(sink, config);
93 }
94 else if ("code".equals(type)) {
95 String code = getCodeSnippet(lines);
96
97 if (path.contains("filetabcharacter")) {
98 code = code.replace("\t", " ");
99 }
100
101 if (code.isBlank()) {
102 final String message = String.format(Locale.ROOT,
103 "Empty code snippet from %s, check"
104 + " for code snippet delimiters in input file.", path
105 );
106 throw new MacroExecutionException(message);
107 }
108
109 writeSnippet(sink, code);
110 }
111 else {
112 final String message = String.format(Locale.ROOT, "Unknown example type: %s", type);
113 throw new MacroExecutionException(message);
114 }
115 }
116
117
118
119
120
121
122
123
124 private static List<String> readFile(String path) throws MacroExecutionException {
125 try {
126 final Path exampleFilePath = Path.of(path);
127 return Files.readAllLines(exampleFilePath);
128 }
129 catch (IOException ioException) {
130 final String message = String.format(Locale.ROOT, "Failed to read %s", path);
131 throw new MacroExecutionException(message, ioException);
132 }
133 }
134
135
136
137
138
139
140
141
142
143 private static String getConfigSnippet(Collection<String> lines) {
144 return lines.stream()
145 .dropWhile(line -> !XML_CONFIG_START.equals(line))
146 .skip(1)
147 .takeWhile(line -> !XML_CONFIG_END.equals(line))
148 .collect(Collectors.joining(NEWLINE));
149 }
150
151
152
153
154
155
156
157
158 private static String getCodeSnippet(Collection<String> lines) {
159 return lines.stream()
160 .dropWhile(line -> !line.contains(CODE_SNIPPET_START))
161 .skip(1)
162 .takeWhile(line -> !line.contains(CODE_SNIPPET_END))
163 .collect(Collectors.joining(NEWLINE));
164 }
165
166
167
168
169
170
171
172 private static void writeSnippet(Sink sink, String snippet) {
173 sink.verbatim(SinkEventAttributeSet.BOXED);
174 final String text = NEWLINE
175 + String.join(NEWLINE, snippet.stripTrailing(), INDENTATION);
176 sink.text(text);
177 sink.verbatim_();
178 }
179 }