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.checks.header;
21
22 import java.io.BufferedInputStream;
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.io.LineNumberReader;
26 import java.io.Reader;
27 import java.io.StringReader;
28 import java.net.URI;
29 import java.nio.charset.Charset;
30 import java.nio.charset.UnsupportedCharsetException;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Set;
34 import java.util.regex.Pattern;
35
36 import com.puppycrawl.tools.checkstyle.PropertyType;
37 import com.puppycrawl.tools.checkstyle.XdocsPropertyType;
38 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
40 import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
41 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42
43
44
45
46
47 public abstract class AbstractHeaderCheck extends AbstractFileSetCheck
48 implements ExternalResourceHolder {
49
50
51 private static final Pattern ESCAPED_LINE_FEED_PATTERN = Pattern.compile("\\\\n");
52
53
54 private final List<String> readerLines = new ArrayList<>();
55
56
57 private URI headerFile;
58
59
60 @XdocsPropertyType(PropertyType.STRING)
61 private Charset charset;
62
63
64
65
66 protected AbstractHeaderCheck() {
67
68 }
69
70
71
72
73
74 protected abstract void postProcessHeaderLines();
75
76
77
78
79
80
81 protected List<String> getHeaderLines() {
82 return List.copyOf(readerLines);
83 }
84
85
86
87
88
89
90 public void setCharset(String charset) {
91 this.charset = createCharset(charset);
92 }
93
94
95
96
97
98
99
100 public void setHeaderFile(URI uri) throws CheckstyleException {
101 if (uri == null) {
102 throw new CheckstyleException(
103 "property 'headerFile' is missing or invalid in module "
104 + getConfiguration().getName());
105 }
106
107 headerFile = uri;
108 }
109
110
111
112
113
114
115 private void loadHeaderFile() throws CheckstyleException {
116 checkHeaderNotInitialized();
117 try (Reader headerReader = new InputStreamReader(new BufferedInputStream(
118 headerFile.toURL().openStream()), charset)) {
119 loadHeader(headerReader);
120 }
121 catch (final IOException exc) {
122 throw new CheckstyleException(
123 "unable to load header file " + headerFile, exc);
124 }
125 }
126
127
128
129
130
131
132 private void checkHeaderNotInitialized() {
133 if (!readerLines.isEmpty()) {
134 throw new IllegalArgumentException(
135 "header has already been set - "
136 + "set either header or headerFile, not both");
137 }
138 }
139
140
141
142
143
144
145
146
147 private static Charset createCharset(String name) {
148 if (!Charset.isSupported(name)) {
149 final String message = "unsupported charset: '" + name + "'";
150 throw new UnsupportedCharsetException(message);
151 }
152 return Charset.forName(name);
153 }
154
155
156
157
158
159
160
161
162
163 public void setHeader(String header) {
164 if (!CommonUtil.isBlank(header)) {
165 checkHeaderNotInitialized();
166
167 final String headerExpandedNewLines = ESCAPED_LINE_FEED_PATTERN
168 .matcher(header).replaceAll("\n");
169
170 try (Reader headerReader = new StringReader(headerExpandedNewLines)) {
171 loadHeader(headerReader);
172 }
173 catch (final IOException exc) {
174 throw new IllegalArgumentException("unable to load header", exc);
175 }
176 }
177 }
178
179
180
181
182
183
184
185 private void loadHeader(final Reader headerReader) throws IOException {
186 try (LineNumberReader lnr = new LineNumberReader(headerReader)) {
187 String line;
188 do {
189 line = lnr.readLine();
190 if (line != null) {
191 readerLines.add(line);
192 }
193 } while (line != null);
194 postProcessHeaderLines();
195 }
196 }
197
198 @Override
199 protected final void finishLocalSetup() throws CheckstyleException {
200 if (headerFile != null) {
201 loadHeaderFile();
202 }
203 }
204
205 @Override
206 public Set<String> getExternalResourceLocations() {
207 final Set<String> result;
208
209 if (headerFile == null) {
210 result = Set.of();
211 }
212 else {
213 result = Set.of(headerFile.toASCIIString());
214 }
215
216 return result;
217 }
218
219 }