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