1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.macro.snippet;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 import org.apache.maven.doxia.macro.AbstractMacro;
32 import org.apache.maven.doxia.macro.MacroExecutionException;
33 import org.apache.maven.doxia.macro.MacroRequest;
34 import org.apache.maven.doxia.sink.Sink;
35 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42 @Singleton
43 @Named("snippet")
44 public class SnippetMacro extends AbstractMacro {
45 private static final Logger LOGGER = LoggerFactory.getLogger(SnippetMacro.class);
46
47
48
49
50 private static Map<String, String> cache = new HashMap<>();
51
52 private static final int HOUR = 60;
53
54
55
56
57 private long timeout = HOUR * HOUR * 1000;
58
59
60
61
62 private static Map<String, Long> timeCached = new HashMap<>();
63
64
65
66
67 private boolean debug = false;
68
69
70
71
72 private boolean ignoreDownloadError = true;
73
74
75 public void execute(Sink sink, MacroRequest request) throws MacroExecutionException {
76 String id = (String) request.getParameter("id");
77
78 String urlParam = (String) request.getParameter("url");
79
80 String fileParam = (String) request.getParameter("file");
81
82 String debugParam = (String) request.getParameter("debug");
83
84 if (debugParam != null) {
85 this.debug = Boolean.parseBoolean(debugParam);
86 }
87
88 String ignoreDownloadErrorParam = (String) request.getParameter("ignoreDownloadError");
89
90 if (ignoreDownloadErrorParam != null) {
91 this.ignoreDownloadError = Boolean.parseBoolean(ignoreDownloadErrorParam);
92 }
93
94 boolean verbatim = true;
95
96 String verbatimParam = (String) request.getParameter("verbatim");
97
98 if (verbatimParam != null && !"".equals(verbatimParam)) {
99 verbatim = Boolean.valueOf(verbatimParam);
100 }
101
102 boolean source = true;
103
104 String sourceParam = (String) request.getParameter("source");
105
106 if (sourceParam != null && !"".equals(sourceParam)) {
107 source = Boolean.valueOf(sourceParam);
108 }
109
110 String encoding = (String) request.getParameter("encoding");
111
112 URL url;
113
114 if (!(urlParam == null || urlParam.isEmpty())) {
115 try {
116 url = new URL(urlParam);
117 } catch (MalformedURLException e) {
118 throw new IllegalArgumentException(urlParam + " is a malformed URL", e);
119 }
120 } else if (!(fileParam == null || fileParam.isEmpty())) {
121 File f = new File(fileParam);
122
123 if (!f.isAbsolute()) {
124 f = new File(request.getBasedir(), fileParam);
125 }
126
127 try {
128 url = f.toURI().toURL();
129 } catch (MalformedURLException e) {
130 throw new IllegalArgumentException(fileParam + " is a malformed URL", e);
131 }
132 } else {
133 throw new IllegalArgumentException("Either the 'url' or the 'file' param has to be provided");
134 }
135
136 StringBuffer snippet;
137
138 try {
139 snippet = getSnippet(url, encoding, id);
140 } catch (IOException e) {
141 throw new MacroExecutionException("Error reading snippet", e);
142 }
143
144 if (verbatim) {
145 sink.verbatim(source ? SinkEventAttributeSet.SOURCE : null);
146
147 sink.text(snippet.toString());
148
149 sink.verbatim_();
150 } else {
151 sink.rawText(snippet.toString());
152 }
153 }
154
155
156
157
158
159
160
161
162
163
164 private StringBuffer getSnippet(URL url, String encoding, String id) throws IOException {
165 StringBuffer result;
166
167 String cachedSnippet = getCachedSnippet(url, id);
168
169 if (cachedSnippet != null) {
170 result = new StringBuffer(cachedSnippet);
171
172 if (debug) {
173 result.append("(Served from cache)");
174 }
175 } else {
176 try {
177 result = new SnippetReader(url, encoding).readSnippet(id);
178 cacheSnippet(url, id, result.toString());
179 if (debug) {
180 result.append("(Fetched from url, cache content ")
181 .append(cache)
182 .append(")");
183 }
184 } catch (IOException e) {
185 if (ignoreDownloadError) {
186 LOGGER.debug("Exception while reading '{}'", url, e);
187 result = new StringBuffer("Error during retrieving content skip as ignoreDownloadError activated.");
188 } else {
189 throw e;
190 }
191 }
192 }
193 return result;
194 }
195
196
197
198
199
200
201
202
203 private String getCachedSnippet(URL url, String id) {
204 if (isCacheTimedout(url, id)) {
205 removeFromCache(url, id);
206 }
207 return cache.get(globalSnippetId(url, id));
208 }
209
210
211
212
213
214
215
216
217
218 boolean isCacheTimedout(URL url, String id) {
219 return timeInCache(url, id) >= timeout;
220 }
221
222
223
224
225
226
227
228
229 long timeInCache(URL url, String id) {
230 return System.currentTimeMillis() - getTimeCached(url, id);
231 }
232
233
234
235
236
237
238
239
240 long getTimeCached(URL url, String id) {
241 String globalId = globalSnippetId(url, id);
242
243 return timeCached.containsKey(globalId) ? timeCached.get(globalId) : 0;
244 }
245
246
247
248
249
250
251
252 private void removeFromCache(URL url, String id) {
253 String globalId = globalSnippetId(url, id);
254
255 timeCached.remove(globalId);
256
257 cache.remove(globalId);
258 }
259
260
261
262
263
264
265
266
267
268 private String globalSnippetId(URL url, String id) {
269 if (id == null || id.isEmpty()) {
270 return url.toString();
271 }
272
273 return url + " " + id;
274 }
275
276
277
278
279
280
281
282
283 public void cacheSnippet(URL url, String id, String content) {
284 cache.put(globalSnippetId(url, id), content);
285
286 timeCached.put(globalSnippetId(url, id), System.currentTimeMillis());
287 }
288
289
290
291
292
293
294 public void setCacheTimeout(int time) {
295 this.timeout = time;
296 }
297 }