1 package org.apache.maven.report.projectinfo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.validator.UrlValidator;
23 import org.apache.maven.doxia.sink.Sink;
24 import org.apache.maven.model.License;
25 import org.apache.maven.project.MavenProject;
26 import org.apache.maven.reporting.AbstractMavenReportRenderer;
27 import org.apache.maven.settings.Settings;
28 import org.codehaus.plexus.i18n.I18N;
29 import org.codehaus.plexus.util.StringUtils;
30
31 import java.io.File;
32 import java.io.IOException;
33 import java.net.MalformedURLException;
34 import java.net.URL;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40
41
42
43
44
45
46
47
48
49 public class LicenseReport
50 extends AbstractProjectInfoReport
51 {
52
53
54
55
56
57
58
59
60
61
62
63 private Settings settings;
64
65
66
67
68
69
70 private boolean offline;
71
72
73
74
75
76
77 public String getName( Locale locale )
78 {
79 return i18n.getString( "project-info-report", locale, "report.license.name" );
80 }
81
82
83 public String getDescription( Locale locale )
84 {
85 return i18n.getString( "project-info-report", locale, "report.license.description" );
86 }
87
88
89 public void executeReport( Locale locale )
90 {
91 LicenseRenderer r = new LicenseRenderer( getSink(), getProject(), i18n, locale, settings );
92
93 r.render();
94 }
95
96
97 public boolean canGenerateReport()
98 {
99 if ( !offline )
100 {
101 return true;
102 }
103
104 List licenses = project.getModel().getLicenses();
105 for ( Iterator i = licenses.iterator(); i.hasNext(); )
106 {
107 License license = (License) i.next();
108
109 String url = license.getUrl();
110
111 URL licenseUrl = null;
112 try
113 {
114 licenseUrl = getLicenseURL( project, url );
115 }
116 catch ( MalformedURLException e )
117 {
118 getLog().error( e.getMessage() );
119 }
120 catch ( IOException e )
121 {
122 getLog().error( e.getMessage() );
123 }
124
125 if ( licenseUrl != null && licenseUrl.getProtocol().equals( "file" ) )
126 {
127 return true;
128 }
129 }
130
131 return false;
132 }
133
134
135 public String getOutputName()
136 {
137 return "license";
138 }
139
140
141
142
143
144
145
146
147 protected static URL getLicenseURL( MavenProject project, String url )
148 throws MalformedURLException, IOException
149 {
150 URL licenseUrl = null;
151 UrlValidator urlValidator = new UrlValidator( UrlValidator.ALLOW_ALL_SCHEMES );
152
153
154
155
156 if ( urlValidator.isValid( url ) || StringUtils.defaultString( url ).startsWith( "file://" ) )
157 {
158 try
159 {
160 licenseUrl = new URL( url );
161 }
162 catch ( MalformedURLException e )
163 {
164 throw new MalformedURLException( "The license url '" + url + "' seems to be invalid: "
165 + e.getMessage() );
166 }
167 }
168 else
169 {
170 File licenseFile = new File( project.getBasedir(), url );
171 if ( !licenseFile.exists() )
172 {
173
174
175 licenseFile = new File( url );
176 }
177 if ( !licenseFile.exists() )
178 {
179 throw new IOException( "Maven can't find the file '" + licenseFile + "' on the system." );
180 }
181 try
182 {
183 licenseUrl = licenseFile.toURL();
184 }
185 catch ( MalformedURLException e )
186 {
187 throw new MalformedURLException( "The license url '" + url + "' seems to be invalid: "
188 + e.getMessage() );
189 }
190 }
191
192 return licenseUrl;
193 }
194
195
196
197
198
199
200
201
202 private static class LicenseRenderer
203 extends AbstractMavenReportRenderer
204 {
205 private MavenProject project;
206
207 private Settings settings;
208
209 private I18N i18n;
210
211 private Locale locale;
212
213 LicenseRenderer( Sink sink, MavenProject project, I18N i18n, Locale locale, Settings settings )
214 {
215 super( sink );
216
217 this.project = project;
218
219 this.settings = settings;
220
221 this.i18n = i18n;
222
223 this.locale = locale;
224 }
225
226
227 public String getTitle()
228 {
229 return i18n.getString( "project-info-report", locale, "report.license.title" );
230 }
231
232
233 public void renderBody()
234 {
235 List licenses = project.getModel().getLicenses();
236
237 if ( licenses.isEmpty() )
238 {
239 startSection( getTitle() );
240
241 paragraph( i18n.getString( "project-info-report", locale, "report.license.nolicense" ) );
242
243 endSection();
244
245 return;
246 }
247
248
249 startSection( i18n.getString( "project-info-report", locale, "report.license.overview.title" ) );
250
251 paragraph( i18n.getString( "project-info-report", locale, "report.license.overview.intro" ) );
252
253 endSection();
254
255
256 startSection( i18n.getString( "project-info-report", locale, "report.license.title" ) );
257
258 for ( Iterator i = licenses.iterator(); i.hasNext(); )
259 {
260 License license = (License) i.next();
261
262 String name = license.getName();
263 String url = license.getUrl();
264 String comments = license.getComments();
265
266 startSection( name );
267
268 if ( !StringUtils.isEmpty( comments ) )
269 {
270 paragraph( comments );
271 }
272
273 if ( url != null )
274 {
275 URL licenseUrl = null;
276 try
277 {
278 licenseUrl = getLicenseURL( project, url );
279 }
280 catch ( MalformedURLException e )
281 {
282
283 paragraph( e.getMessage() );
284 }
285 catch ( IOException e )
286 {
287
288 paragraph( e.getMessage() );
289 }
290
291 if ( licenseUrl != null )
292 {
293 String licenseContent = null;
294 try
295 {
296
297 licenseContent = ProjectInfoReportUtils.getInputStream( licenseUrl, settings );
298 }
299 catch ( IOException e )
300 {
301 paragraph( "Can't read the url [" + licenseUrl + "] : " + e.getMessage() );
302 }
303
304 if ( licenseContent != null )
305 {
306
307 String licenseContentLC = licenseContent.toLowerCase( Locale.ENGLISH );
308 int bodyStart = licenseContentLC.indexOf( "<body" );
309 int bodyEnd = licenseContentLC.indexOf( "</body>" );
310 if ( ( licenseContentLC.startsWith( "<!doctype html" )
311 || licenseContentLC.startsWith( "<html>" ) ) && bodyStart >= 0 && bodyEnd >= 0 )
312 {
313 bodyStart = licenseContentLC.indexOf( ">", bodyStart ) + 1;
314 String body = licenseContent.substring( bodyStart, bodyEnd );
315
316 link( licenseUrl.toExternalForm(), "[Original text]" );
317 paragraph( "Copy of the license follows." );
318
319 body = replaceRelativeLinks( body, baseURL( licenseUrl ).toExternalForm() );
320 sink.rawText( body );
321 }
322 else
323 {
324 verbatimText( licenseContent );
325 }
326 }
327 }
328 }
329
330 endSection();
331 }
332
333 endSection();
334 }
335
336 private static URL baseURL( URL aUrl )
337 {
338 String urlTxt = aUrl.toExternalForm();
339 int lastSlash = urlTxt.lastIndexOf( '/' );
340 if ( lastSlash > -1 )
341 {
342 try
343 {
344 return new URL( urlTxt.substring( 0, lastSlash + 1 ) );
345 }
346 catch ( MalformedURLException e )
347 {
348 throw new AssertionError( e );
349 }
350 }
351
352 return aUrl;
353 }
354
355 private static String replaceRelativeLinks( String html, String baseURL )
356 {
357 String url = baseURL;
358 if ( !url.endsWith( "/" ) )
359 {
360 url += "/";
361 }
362
363 String serverURL = url.substring( 0, url.indexOf( '/', url.indexOf( "//" ) + 2 ) );
364
365 String content = replaceParts( html, url, serverURL, "[aA]", "[hH][rR][eE][fF]" );
366 content = replaceParts( content, url, serverURL, "[iI][mM][gG]", "[sS][rR][cC]" );
367 return content;
368 }
369
370 private static String replaceParts( String html, String baseURL, String serverURL, String tagPattern,
371 String attributePattern )
372 {
373 Pattern anchor = Pattern.compile(
374 "(<\\s*" + tagPattern + "\\s+[^>]*" + attributePattern + "\\s*=\\s*\")([^\"]*)\"([^>]*>)" );
375 StringBuffer sb = new StringBuffer( html );
376
377 int indx = 0;
378 boolean done = false;
379 while ( !done )
380 {
381 Matcher mAnchor = anchor.matcher( sb );
382 if ( mAnchor.find( indx ) )
383 {
384 indx = mAnchor.end( 3 );
385
386 if ( mAnchor.group( 2 ).startsWith( "#" ) )
387 {
388
389 }
390 if ( mAnchor.group( 2 ).startsWith( "/" ) )
391 {
392
393 sb.insert( mAnchor.start( 2 ), serverURL );
394 indx += serverURL.length();
395 }
396 else if ( mAnchor.group( 2 ).indexOf( ':' ) < 0 )
397 {
398
399 sb.insert( mAnchor.start( 2 ), baseURL );
400 indx += baseURL.length();
401 }
402 }
403 else
404 {
405 done = true;
406 }
407 }
408 return sb.toString();
409 }
410 }
411 }