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.FileInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.SortedMap;
30 import java.util.SortedSet;
31 import java.util.TreeMap;
32
33 import org.apache.commons.collections.CollectionUtils;
34 import org.apache.commons.io.FileUtils;
35 import org.apache.commons.io.IOUtils;
36 import org.apache.commons.lang.StringUtils;
37 import org.apache.maven.plugin.MojoFailureException;
38 import org.apache.maven.plugin.logging.Log;
39 import org.apache.maven.project.MavenProject;
40 import org.apache.maven.project.ProjectBuildingException;
41 import org.codehaus.mojo.license.model.LicenseMap;
42 import org.springframework.core.io.DefaultResourceLoader;
43 import org.springframework.core.io.Resource;
44 import org.springframework.core.io.ResourceLoader;
45
46
47
48
49
50
51
52 public abstract class AbstractAddThirdPartyMojo extends AbstractLicenseMojo {
53
54
55
56
57
58
59
60
61
62 protected File outputDirectory;
63
64
65
66
67
68
69
70
71 protected String thirdPartyFilename;
72
73
74
75
76
77
78
79 protected boolean useMissingFile;
80
81
82
83
84
85
86
87 protected File missingFile;
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 thirdPartyTool;
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 File file = new File(location);
267 if (file.exists()) {
268 return true;
269 }
270 ResourceLoader loader = new DefaultResourceLoader();
271 Resource resource = loader.getResource(location);
272 return resource.exists();
273 }
274
275 protected InputStream getInputStream(String location) throws IOException {
276 File file = new File(location);
277 if (file.exists()) {
278 return new FileInputStream(file);
279 }
280 ResourceLoader loader = new DefaultResourceLoader();
281 Resource resource = loader.getResource(location);
282 if (!resource.exists()) {
283 throw new IllegalArgumentException("Can't open an input stream for " + location);
284 } else {
285 return resource.getInputStream();
286 }
287 }
288
289 protected File copyToFileSystem(String location) {
290 File temp = new File(getProject().getBuild().getDirectory() + "/license/THIRD-PARTY.properties");
291 return copyToFileSystem(location, temp);
292 }
293
294 protected File copyToFileSystem(String location, File file) {
295 InputStream in = null;
296 OutputStream out = null;
297 try {
298 in = getInputStream(location);
299 out = FileUtils.openOutputStream(file);
300 IOUtils.copy(in, out);
301 getLog().debug("Copied " + location + " to " + file);
302 return file;
303 } catch (IOException e) {
304 throw new IllegalArgumentException(e);
305 } finally {
306 IOUtils.closeQuietly(in);
307 IOUtils.closeQuietly(out);
308 }
309 }
310
311 @Override
312 protected void init() throws Exception {
313 if (exists(getArtifactLicenseMapping())) {
314
315
316
317 File propertiesFile = copyToFileSystem(getArtifactLicenseMapping());
318
319 setMissingFile(propertiesFile);
320 }
321
322 Log log = getLog();
323 if (log.isDebugEnabled()) {
324
325 setVerbose(true);
326 }
327
328
329
330 File file = new File(getOutputDirectory(), getThirdPartyFilename());
331
332 setThirdPartyFile(file);
333
334 long buildTimestamp = getBuildTimestamp();
335
336 if (isVerbose()) {
337 log.info("Build start at : " + buildTimestamp);
338 log.info("third-party file : " + file.lastModified());
339 }
340
341 setDoGenerate(isForce() || !file.exists() || buildTimestamp > file.lastModified());
342
343 if (isGenerateBundle()) {
344 File bundleFile = FileUtil.getFile(getOutputDirectory(), getBundleThirdPartyPath());
345 if (isVerbose()) {
346 log.info("bundle third-party file : " + bundleFile.lastModified());
347 }
348 setDoGenerateBundle(isForce() || !bundleFile.exists() || buildTimestamp > bundleFile.lastModified());
349 } else {
350
351 setDoGenerateBundle(false);
352 }
353
354
355
356
357 projectDependencies = loadDependencies();
358
359
360
361 licenseMap = createLicenseMap(projectDependencies);
362
363
364 SortedSet<MavenProject> unsafeDependencies = getThirdPartyTool().getProjectsWithNoLicense(licenseMap,
365 isVerbose());
366
367 setUnsafeDependencies(unsafeDependencies);
368
369 if (!CollectionUtils.isEmpty(unsafeDependencies) && isUseMissingFile() && isDoGenerate()) {
370
371 unsafeMappings = createUnsafeMapping();
372 }
373
374 if (!CollectionUtils.isEmpty(licenseMerges)) {
375
376
377 Map<String, String[]> mergedLicenses = new HashMap<String, String[]>();
378
379 for (String merge : licenseMerges) {
380 merge = merge.trim();
381 String[] split = merge.split("\\|");
382
383 String mainLicense = split[0];
384
385 if (mergedLicenses.containsKey(mainLicense)) {
386
387
388
389 throw new MojoFailureException(
390 "The merge main license "
391 + mainLicense
392 + " was already registred in the "
393 + "configuration, please use only one such entry as describe in example "
394 + "http://mojo.codehaus.org/license-maven-plugin/examples/example-thirdparty.html#Merge_licenses.");
395 }
396 mergedLicenses.put(mainLicense, split);
397 }
398
399
400
401 for (String[] mergedLicense : mergedLicenses.values()) {
402 if (isVerbose()) {
403 getLog().info("Will merge " + Arrays.toString(mergedLicense) + "");
404 }
405
406 thirdPartyTool.mergeLicenses(licenseMap, mergedLicense);
407 }
408 }
409 }
410
411
412
413
414 protected LicenseMap createLicenseMap(SortedMap<String, MavenProject> dependencies) {
415 LicenseMap licenseMap = new LicenseMap();
416 for (MavenProject dependency : dependencies.values()) {
417 thirdPartyTool.addLicense(licenseMap, dependency, dependency.getLicenses());
418 }
419 return licenseMap;
420 }
421
422 protected boolean checkUnsafeDependencies() {
423 SortedSet<MavenProject> unsafeDependencies = getUnsafeDependencies();
424 boolean unsafe = !CollectionUtils.isEmpty(unsafeDependencies);
425 if (unsafe) {
426 Log log = getLog();
427 log.debug("There are " + unsafeDependencies.size() + " dependencies with no license :");
428 for (MavenProject dep : unsafeDependencies) {
429
430
431 log.debug(" - " + MojoHelper.getArtifactId(dep.getArtifact()));
432 }
433 }
434 return unsafe;
435 }
436
437 protected void writeThirdPartyFile() throws IOException {
438
439 Log log = getLog();
440 LicenseMap licenseMap = getLicenseMap();
441 File target = getThirdPartyFile();
442
443 if (isDoGenerate()) {
444 StringBuilder sb = new StringBuilder();
445 if (licenseMap.isEmpty()) {
446 sb.append(NO_DEPENDENCIES_MESSAGE);
447 } else {
448 if (isGroupByLicense()) {
449
450
451 sb.append("List of third-party dependencies grouped by " + "their license type.");
452 for (String licenseName : licenseMap.keySet()) {
453 SortedSet<MavenProject> projects = licenseMap.get(licenseName);
454
455
456 if (projects == null || projects.size() == 0) {
457 continue;
458 }
459
460 sb.append("\n\n").append(licenseName).append(" : ");
461
462 for (MavenProject mavenProject : projects) {
463 String s = MojoHelper.getArtifactName(mavenProject);
464 sb.append("\n * ").append(s);
465 }
466 }
467
468 } else {
469
470
471 SortedMap<MavenProject, String[]> map = licenseMap.toDependencyMap();
472
473 sb.append("List of ").append(map.size()).append(" third-party dependencies.\n");
474
475 List<String> lines = new ArrayList<String>();
476
477 for (Map.Entry<MavenProject, String[]> entry : map.entrySet()) {
478 String artifact = MojoHelper.getArtifactName(entry.getKey());
479 StringBuilder buffer = new StringBuilder();
480 for (String license : entry.getValue()) {
481 buffer.append(" (").append(license).append(")");
482 }
483 String licenses = buffer.toString();
484 String line = licenses + " " + artifact;
485 lines.add(line);
486 }
487
488 Collections.sort(lines);
489 for (String line : lines) {
490 sb.append('\n').append(line);
491 }
492 lines.clear();
493 }
494 }
495 String content = sb.toString();
496
497 log.info("Writing third-party file to " + target);
498 if (isVerbose()) {
499 log.info(content);
500 }
501
502 FileUtil.writeString(target, content, getEncoding());
503 }
504
505 if (isDoGenerateBundle()) {
506
507
508 File bundleTarget = FileUtil.getFile(getOutputDirectory(), getBundleThirdPartyPath());
509 log.info("Writing bundled third-party file to " + bundleTarget);
510 FileUtil.copyFile(target, bundleTarget);
511 }
512 }
513
514 public boolean isGroupByLicense() {
515 return groupByLicense;
516 }
517
518 public void setGroupByLicense(boolean groupByLicense) {
519 this.groupByLicense = groupByLicense;
520 }
521
522 public File getOutputDirectory() {
523 return outputDirectory;
524 }
525
526 public String getThirdPartyFilename() {
527 return thirdPartyFilename;
528 }
529
530 public String getBundleThirdPartyPath() {
531 return bundleThirdPartyPath;
532 }
533
534 public boolean isGenerateBundle() {
535 return generateBundle;
536 }
537
538 public boolean isFailIfWarning() {
539 return failIfWarning;
540 }
541
542 public SortedMap<String, MavenProject> getProjectDependencies() {
543 return projectDependencies;
544 }
545
546 public SortedSet<MavenProject> getUnsafeDependencies() {
547 return unsafeDependencies;
548 }
549
550 public void setUnsafeDependencies(SortedSet<MavenProject> unsafeDependencies) {
551 this.unsafeDependencies = unsafeDependencies;
552 }
553
554 public File getThirdPartyFile() {
555 return thirdPartyFile;
556 }
557
558 public LicenseMap getLicenseMap() {
559 return licenseMap;
560 }
561
562 public void setOutputDirectory(File outputDirectory) {
563 this.outputDirectory = outputDirectory;
564 }
565
566 public void setThirdPartyFilename(String thirdPartyFilename) {
567 this.thirdPartyFilename = thirdPartyFilename;
568 }
569
570 public void setBundleThirdPartyPath(String bundleThirdPartyPath) {
571 this.bundleThirdPartyPath = bundleThirdPartyPath;
572 }
573
574 public void setGenerateBundle(boolean generateBundle) {
575 this.generateBundle = generateBundle;
576 }
577
578 public void setThirdPartyFile(File thirdPartyFile) {
579 this.thirdPartyFile = thirdPartyFile;
580 }
581
582 public boolean isUseMissingFile() {
583 return useMissingFile;
584 }
585
586 public File getMissingFile() {
587 return missingFile;
588 }
589
590 public void setUseMissingFile(boolean useMissingFile) {
591 this.useMissingFile = useMissingFile;
592 }
593
594 public void setMissingFile(File missingFile) {
595 this.missingFile = missingFile;
596 }
597
598 public void setFailIfWarning(boolean failIfWarning) {
599 this.failIfWarning = failIfWarning;
600 }
601
602 public SortedProperties getUnsafeMappings() {
603 return unsafeMappings;
604 }
605
606 public boolean isForce() {
607 return force;
608 }
609
610 public boolean isDoGenerate() {
611 return doGenerate;
612 }
613
614 public void setForce(boolean force) {
615 this.force = force;
616 }
617
618 public void setDoGenerate(boolean doGenerate) {
619 this.doGenerate = doGenerate;
620 }
621
622 public boolean isDoGenerateBundle() {
623 return doGenerateBundle;
624 }
625
626 public void setDoGenerateBundle(boolean doGenerateBundle) {
627 this.doGenerateBundle = doGenerateBundle;
628 }
629
630 public List<String> getExcludedScopes() {
631 String[] split = excludedScopes == null ? new String[0] : excludedScopes.split(",");
632 return Arrays.asList(split);
633 }
634
635 public void setExcludedScopes(String excludedScopes) {
636 this.excludedScopes = excludedScopes;
637 }
638
639 public List<String> getIncludedScopes() {
640 String[] split = includedScopes == null ? new String[0] : includedScopes.split(",");
641 return Arrays.asList(split);
642 }
643
644 public void setIncludedScopes(String includedScopes) {
645 this.includedScopes = includedScopes;
646 }
647
648 public String getExcludedGroups() {
649 return excludedGroups;
650 }
651
652 public void setExcludedGroups(String excludedGroups) {
653 this.excludedGroups = excludedGroups;
654 }
655
656 public String getIncludedGroups() {
657 return includedGroups;
658 }
659
660 public void setIncludedGroups(String includedGroups) {
661 this.includedGroups = includedGroups;
662 }
663
664 public String getExcludedArtifacts() {
665 return excludedArtifacts;
666 }
667
668 public void setExcludedArtifacts(String excludedArtifacts) {
669 this.excludedArtifacts = excludedArtifacts;
670 }
671
672 public String getIncludedArtifacts() {
673 return includedArtifacts;
674 }
675
676 public void setIncludedArtifacts(String includedArtifacts) {
677 this.includedArtifacts = includedArtifacts;
678 }
679
680 public ThirdPartyTool getThirdPartyTool() {
681 return thirdPartyTool;
682 }
683
684 public void setThirdPartyTool(ThirdPartyTool thridPartyTool) {
685 this.thirdPartyTool = thridPartyTool;
686 }
687
688 public String getArtifactLicenseMapping() {
689 return artifactLicenseMapping;
690 }
691
692 public void setArtifactLicenseMapping(String artifactLicenseMapping) {
693 this.artifactLicenseMapping = artifactLicenseMapping;
694 }
695 }