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 }