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