1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codehaus.mojo.license;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.SortedMap;
29 import java.util.SortedSet;
30 import java.util.TreeMap;
31
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.io.FileUtils;
34 import org.apache.commons.io.IOUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugin.logging.Log;
38 import org.apache.maven.project.MavenProject;
39 import org.apache.maven.project.ProjectBuildingException;
40 import org.codehaus.mojo.license.model.LicenseMap;
41 import org.springframework.core.io.DefaultResourceLoader;
42 import org.springframework.core.io.Resource;
43 import org.springframework.core.io.ResourceLoader;
44
45
46
47
48
49
50
51 public abstract class AbstractAddThirdPartyMojo extends AbstractLicenseMojo {
52
53
54
55
56
57
58
59
60
61 protected File outputDirectory;
62
63
64
65
66
67
68
69
70 protected String thirdPartyFilename;
71
72
73
74
75
76
77
78 protected boolean useMissingFile;
79
80
81
82
83
84
85
86 protected File missingFile;
87
88
89
90
91
92
93
94
95
96 protected String artifactLicenseMapping;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 protected List<String> licenseMerges;
116
117
118
119
120
121
122
123
124
125
126 protected String bundleThirdPartyPath;
127
128
129
130
131
132
133
134
135
136
137 protected boolean generateBundle;
138
139
140
141
142
143
144
145 protected boolean force;
146
147
148
149
150
151
152
153 protected boolean failIfWarning;
154
155
156
157
158
159
160
161
162
163
164
165 protected boolean groupByLicense;
166
167
168
169
170
171
172
173 protected String excludedScopes;
174
175
176
177
178
179
180
181 protected String includedScopes;
182
183
184
185
186
187
188
189 protected String excludedGroups;
190
191
192
193
194
195
196
197 protected String includedGroups;
198
199
200
201
202
203
204
205 protected String excludedArtifacts;
206
207
208
209
210
211
212
213 protected String includedArtifacts;
214
215
216
217
218
219
220
221 protected boolean includeTransitiveDependencies;
222
223
224
225
226
227
228
229
230 private ThirdPartyTool thridPartyTool;
231
232 private SortedMap<String, MavenProject> projectDependencies;
233
234 private LicenseMap licenseMap;
235
236 private SortedSet<MavenProject> unsafeDependencies;
237
238 private File thirdPartyFile;
239
240 private SortedProperties unsafeMappings;
241
242 private boolean doGenerate;
243
244 private boolean doGenerateBundle;
245
246 public static final String NO_DEPENDENCIES_MESSAGE = "the project has no dependencies.";
247
248 private static SortedMap<String, MavenProject> artifactCache;
249
250 public static SortedMap<String, MavenProject> getArtifactCache() {
251 if (artifactCache == null) {
252 artifactCache = new TreeMap<String, MavenProject>();
253 }
254 return artifactCache;
255 }
256
257 protected abstract SortedMap<String, MavenProject> loadDependencies();
258
259 protected abstract SortedProperties createUnsafeMapping() throws ProjectBuildingException, IOException,
260 ThirdPartyToolException;
261
262 protected boolean exists(String location) {
263 if (StringUtils.isBlank(location)) {
264 return false;
265 }
266 ResourceLoader loader = new DefaultResourceLoader();
267 Resource resource = loader.getResource(location);
268 return resource.exists();
269 }
270
271 protected File copyToFileSystem(String location) {
272 ResourceLoader loader = new DefaultResourceLoader();
273 Resource resource = loader.getResource(location);
274 if (!resource.exists()) {
275 throw new IllegalArgumentException("Can't locate " + location);
276 }
277
278 InputStream in = null;
279 OutputStream out = null;
280 try {
281 in = resource.getInputStream();
282 File temp = new File(getProject().getBuild().getDirectory() + "/license/THIRD-PARTY.properties");
283 out = FileUtils.openOutputStream(temp);
284 IOUtils.copy(in, out);
285 getLog().debug("Created " + temp);
286 return temp;
287 } catch (IOException e) {
288 throw new IllegalArgumentException(e);
289 } finally {
290 IOUtils.closeQuietly(in);
291 IOUtils.closeQuietly(out);
292 }
293 }
294
295 @Override
296 protected void init() throws Exception {
297 if (exists(getArtifactLicenseMapping())) {
298 File propertiesFile = copyToFileSystem(getArtifactLicenseMapping());
299 setMissingFile(propertiesFile);
300 }
301
302 Log log = getLog();
303
304 if (log.isDebugEnabled()) {
305
306
307 setVerbose(true);
308 }
309
310 File file = new File(getOutputDirectory(), getThirdPartyFilename());
311
312 setThirdPartyFile(file);
313
314 long buildTimestamp = getBuildTimestamp();
315
316 if (isVerbose()) {
317 log.info("Build start at : " + buildTimestamp);
318 log.info("third-party file : " + file.lastModified());
319 }
320
321 setDoGenerate(isForce() || !file.exists() || buildTimestamp > file.lastModified());
322
323 if (isGenerateBundle()) {
324
325 File bundleFile = FileUtil.getFile(getOutputDirectory(), getBundleThirdPartyPath());
326
327 if (isVerbose()) {
328 log.info("bundle third-party file : " + bundleFile.lastModified());
329 }
330 setDoGenerateBundle(isForce() || !bundleFile.exists() || buildTimestamp > bundleFile.lastModified());
331 } else {
332
333
334 setDoGenerateBundle(false);
335 }
336
337 projectDependencies = loadDependencies();
338
339 licenseMap = createLicenseMap(projectDependencies);
340
341 SortedSet<MavenProject> unsafeDependencies = getThridPartyTool().getProjectsWithNoLicense(licenseMap,
342 isVerbose());
343
344 setUnsafeDependencies(unsafeDependencies);
345
346 if (!CollectionUtils.isEmpty(unsafeDependencies) && isUseMissingFile() && isDoGenerate()) {
347
348
349 unsafeMappings = createUnsafeMapping();
350 }
351
352 if (!CollectionUtils.isEmpty(licenseMerges)) {
353
354
355 Map<String, String[]> mergedLicenses = new HashMap<String, String[]>();
356
357 for (String merge : licenseMerges) {
358 merge = merge.trim();
359 String[] split = merge.split("\\|");
360
361 String mainLicense = split[0];
362
363 if (mergedLicenses.containsKey(mainLicense)) {
364
365
366
367 throw new MojoFailureException(
368 "The merge main license "
369 + mainLicense
370 + " was already registred in the "
371 + "configuration, please use only one such entry as describe in example "
372 + "http://mojo.codehaus.org/license-maven-plugin/examples/example-thirdparty.html#Merge_licenses.");
373 }
374 mergedLicenses.put(mainLicense, split);
375 }
376
377
378
379 for (String[] mergedLicense : mergedLicenses.values()) {
380 if (isVerbose()) {
381 getLog().info("Will merge " + Arrays.toString(mergedLicense) + "");
382 }
383
384 thridPartyTool.mergeLicenses(licenseMap, mergedLicense);
385 }
386 }
387 }
388
389 protected LicenseMap createLicenseMap(SortedMap<String, MavenProject> dependencies) {
390
391 LicenseMap licenseMap = new LicenseMap();
392
393 for (MavenProject project : dependencies.values()) {
394 thridPartyTool.addLicense(licenseMap, project, project.getLicenses());
395 }
396 return licenseMap;
397 }
398
399 protected boolean checkUnsafeDependencies() {
400 SortedSet<MavenProject> unsafeDependencies = getUnsafeDependencies();
401 boolean unsafe = !CollectionUtils.isEmpty(unsafeDependencies);
402 if (unsafe) {
403 Log log = getLog();
404 log.debug("There is " + unsafeDependencies.size() + " dependencies with no license :");
405 for (MavenProject dep : unsafeDependencies) {
406
407
408 log.info(" - " + MojoHelper.getArtifactId(dep.getArtifact()));
409 }
410 }
411 return unsafe;
412 }
413
414 protected void writeThirdPartyFile() throws IOException {
415
416 Log log = getLog();
417 LicenseMap licenseMap = getLicenseMap();
418 File target = getThirdPartyFile();
419
420 if (isDoGenerate()) {
421 StringBuilder sb = new StringBuilder();
422 if (licenseMap.isEmpty()) {
423 sb.append(NO_DEPENDENCIES_MESSAGE);
424 } else {
425 if (isGroupByLicense()) {
426
427
428 sb.append("List of third-party dependencies grouped by " + "their license type.");
429 for (String licenseName : licenseMap.keySet()) {
430 SortedSet<MavenProject> projects = licenseMap.get(licenseName);
431 sb.append("\n\n").append(licenseName).append(" : ");
432
433 for (MavenProject mavenProject : projects) {
434 String s = MojoHelper.getArtifactName(mavenProject);
435 sb.append("\n * ").append(s);
436 }
437 }
438
439 } else {
440
441
442 SortedMap<MavenProject, String[]> map = licenseMap.toDependencyMap();
443
444 sb.append("List of ").append(map.size()).append(" third-party dependencies.\n");
445
446 List<String> lines = new ArrayList<String>();
447
448 for (Map.Entry<MavenProject, String[]> entry : map.entrySet()) {
449 String artifact = MojoHelper.getArtifactName(entry.getKey());
450 StringBuilder buffer = new StringBuilder();
451 for (String license : entry.getValue()) {
452 buffer.append(" (").append(license).append(")");
453 }
454 String licenses = buffer.toString();
455 String line = licenses + " " + artifact;
456 lines.add(line);
457 }
458
459 Collections.sort(lines);
460 for (String line : lines) {
461 sb.append('\n').append(line);
462 }
463 lines.clear();
464 }
465 }
466 String content = sb.toString();
467
468 log.info("Writing third-party file to " + target);
469 if (isVerbose()) {
470 log.info(content);
471 }
472
473 FileUtil.writeString(target, content, getEncoding());
474 }
475
476 if (isDoGenerateBundle()) {
477
478
479 File bundleTarget = FileUtil.getFile(getOutputDirectory(), getBundleThirdPartyPath());
480 log.info("Writing bundled third-party file to " + bundleTarget);
481 FileUtil.copyFile(target, bundleTarget);
482 }
483 }
484
485 public boolean isGroupByLicense() {
486 return groupByLicense;
487 }
488
489 public void setGroupByLicense(boolean groupByLicense) {
490 this.groupByLicense = groupByLicense;
491 }
492
493 public File getOutputDirectory() {
494 return outputDirectory;
495 }
496
497 public String getThirdPartyFilename() {
498 return thirdPartyFilename;
499 }
500
501 public String getBundleThirdPartyPath() {
502 return bundleThirdPartyPath;
503 }
504
505 public boolean isGenerateBundle() {
506 return generateBundle;
507 }
508
509 public boolean isFailIfWarning() {
510 return failIfWarning;
511 }
512
513 public SortedMap<String, MavenProject> getProjectDependencies() {
514 return projectDependencies;
515 }
516
517 public SortedSet<MavenProject> getUnsafeDependencies() {
518 return unsafeDependencies;
519 }
520
521 public void setUnsafeDependencies(SortedSet<MavenProject> unsafeDependencies) {
522 this.unsafeDependencies = unsafeDependencies;
523 }
524
525 public File getThirdPartyFile() {
526 return thirdPartyFile;
527 }
528
529 public LicenseMap getLicenseMap() {
530 return licenseMap;
531 }
532
533 public void setOutputDirectory(File outputDirectory) {
534 this.outputDirectory = outputDirectory;
535 }
536
537 public void setThirdPartyFilename(String thirdPartyFilename) {
538 this.thirdPartyFilename = thirdPartyFilename;
539 }
540
541 public void setBundleThirdPartyPath(String bundleThirdPartyPath) {
542 this.bundleThirdPartyPath = bundleThirdPartyPath;
543 }
544
545 public void setGenerateBundle(boolean generateBundle) {
546 this.generateBundle = generateBundle;
547 }
548
549 public void setThirdPartyFile(File thirdPartyFile) {
550 this.thirdPartyFile = thirdPartyFile;
551 }
552
553 public boolean isUseMissingFile() {
554 return useMissingFile;
555 }
556
557 public File getMissingFile() {
558 return missingFile;
559 }
560
561 public void setUseMissingFile(boolean useMissingFile) {
562 this.useMissingFile = useMissingFile;
563 }
564
565 public void setMissingFile(File missingFile) {
566 this.missingFile = missingFile;
567 }
568
569 public void setFailIfWarning(boolean failIfWarning) {
570 this.failIfWarning = failIfWarning;
571 }
572
573 public SortedProperties getUnsafeMappings() {
574 return unsafeMappings;
575 }
576
577 public boolean isForce() {
578 return force;
579 }
580
581 public boolean isDoGenerate() {
582 return doGenerate;
583 }
584
585 public void setForce(boolean force) {
586 this.force = force;
587 }
588
589 public void setDoGenerate(boolean doGenerate) {
590 this.doGenerate = doGenerate;
591 }
592
593 public boolean isDoGenerateBundle() {
594 return doGenerateBundle;
595 }
596
597 public void setDoGenerateBundle(boolean doGenerateBundle) {
598 this.doGenerateBundle = doGenerateBundle;
599 }
600
601 public List<String> getExcludedScopes() {
602 String[] split = excludedScopes == null ? new String[0] : excludedScopes.split(",");
603 return Arrays.asList(split);
604 }
605
606 public void setExcludedScopes(String excludedScopes) {
607 this.excludedScopes = excludedScopes;
608 }
609
610 public List<String> getIncludedScopes() {
611 String[] split = includedScopes == null ? new String[0] : includedScopes.split(",");
612 return Arrays.asList(split);
613 }
614
615 public void setIncludedScopes(String includedScopes) {
616 this.includedScopes = includedScopes;
617 }
618
619 public String getExcludedGroups() {
620 return excludedGroups;
621 }
622
623 public void setExcludedGroups(String excludedGroups) {
624 this.excludedGroups = excludedGroups;
625 }
626
627 public String getIncludedGroups() {
628 return includedGroups;
629 }
630
631 public void setIncludedGroups(String includedGroups) {
632 this.includedGroups = includedGroups;
633 }
634
635 public String getExcludedArtifacts() {
636 return excludedArtifacts;
637 }
638
639 public void setExcludedArtifacts(String excludedArtifacts) {
640 this.excludedArtifacts = excludedArtifacts;
641 }
642
643 public String getIncludedArtifacts() {
644 return includedArtifacts;
645 }
646
647 public void setIncludedArtifacts(String includedArtifacts) {
648 this.includedArtifacts = includedArtifacts;
649 }
650
651 public ThirdPartyTool getThridPartyTool() {
652 return thridPartyTool;
653 }
654
655 public void setThridPartyTool(ThirdPartyTool thridPartyTool) {
656 this.thridPartyTool = thridPartyTool;
657 }
658
659 public String getArtifactLicenseMapping() {
660 return artifactLicenseMapping;
661 }
662
663 public void setArtifactLicenseMapping(String artifactLicenseMapping) {
664 this.artifactLicenseMapping = artifactLicenseMapping;
665 }
666 }