Java tutorial
package org.codehaus.mojo.license; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.model.License; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.apache.maven.settings.Proxy; import org.codehaus.mojo.license.api.DependenciesTool; import org.codehaus.mojo.license.api.MavenProjectDependenciesConfigurator; import org.codehaus.mojo.license.model.ProjectLicenseInfo; import org.codehaus.mojo.license.utils.FileUtil; import org.codehaus.mojo.license.utils.LicenseDownloader; import org.codehaus.mojo.license.utils.LicenseSummaryReader; import org.codehaus.mojo.license.utils.LicenseSummaryWriter; import org.codehaus.plexus.util.Base64; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; /** * Created on 23/05/16. * * @author Tony Chemit - chemit@codelutin.com */ public abstract class AbstractDownloadLicensesMojo extends AbstractMojo implements MavenProjectDependenciesConfigurator { // ---------------------------------------------------------------------- // Mojo Parameters // ---------------------------------------------------------------------- /** * Location of the local repository. * * @since 1.0 */ @Parameter(defaultValue = "${localRepository}", readonly = true) private ArtifactRepository localRepository; /** * List of Remote Repositories used by the resolver * * @since 1.0 */ @Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true) private List remoteRepositories; /** * Input file containing a mapping between each dependency and it's license information. * * @since 1.0 */ @Parameter(property = "licensesConfigFile", defaultValue = "${project.basedir}/src/license/licenses.xml") private File licensesConfigFile; /** * The directory to which the dependency licenses should be written. * * @since 1.0 */ @Parameter(property = "licensesOutputDirectory", defaultValue = "${project.build.directory}/generated-resources/licenses") private File licensesOutputDirectory; /** * The output file containing a mapping between each dependency and it's license information. * * @since 1.0 */ @Parameter(property = "licensesOutputFile", defaultValue = "${project.build.directory}/generated-resources/licenses.xml") private File licensesOutputFile; /** * A filter to exclude some scopes. * * @since 1.0 */ @Parameter(property = "license.excludedScopes", defaultValue = "system") private String excludedScopes; /** * A filter to include only some scopes, if let empty then all scopes will be used (no filter). * * @since 1.0 */ @Parameter(property = "license.includedScopes", defaultValue = "") private String includedScopes; /** * Settings offline flag (will not download anything if setted to true). * * @since 1.0 */ @Parameter(defaultValue = "${settings.offline}") private boolean offline; /** * Don't show warnings about bad or missing license files. * * @since 1.0 */ @Parameter(defaultValue = "false") private boolean quiet; /** * Include transitive dependencies when downloading license files. * * @since 1.0 */ @Parameter(defaultValue = "true") private boolean includeTransitiveDependencies; /** * Get declared proxies from the {@code settings.xml} file. * * @since 1.4 */ @Parameter(defaultValue = "${settings.proxies}", readonly = true) private List<Proxy> proxies; /** * A flag to organize the licenses by dependencies. When this is done, each dependency will * get its full license file, even if already downloaded for another dependency. * * @since 1.9 */ @Parameter(property = "license.organizeLicensesByDependencies", defaultValue = "false") protected boolean organizeLicensesByDependencies; /** * The Maven Project Object * * @since 1.0 */ @Parameter(defaultValue = "${project}", readonly = true) private MavenProject project; // ---------------------------------------------------------------------- // Plexus Components // ---------------------------------------------------------------------- /** * Dependencies tool. * * @since 1.0 */ @Component private DependenciesTool dependenciesTool; // ---------------------------------------------------------------------- // Private Fields // ---------------------------------------------------------------------- /** * Keeps a collection of the URLs of the licenses that have been downlaoded. This helps the plugin to avoid * downloading the same license multiple times. */ private Set<String> downloadedLicenseURLs = new HashSet<String>(); /** * Proxy Login/Password encoded(only if usgin a proxy with authentication). * * @since 1.4 */ private String proxyLoginPasswordEncoded; protected abstract boolean isSkip(); protected MavenProject getProject() { return project; } protected abstract Set<MavenProject> getDependencies(); // ---------------------------------------------------------------------- // Mojo Implementation // ---------------------------------------------------------------------- protected SortedMap<String, MavenProject> getDependencies(MavenProject project) { return dependenciesTool.loadProjectDependencies(project, this, localRepository, remoteRepositories, null); } /** * {@inheritDoc} */ public void execute() throws MojoExecutionException { if (offline) { getLog().warn("Offline flag is on, download-licenses goal is skip."); return; } if (isSkip()) { getLog().info("skip flag is on, will skip goal."); return; } initDirectories(); initProxy(); Map<String, ProjectLicenseInfo> configuredDepLicensesMap = new HashMap<String, ProjectLicenseInfo>(); // License info from previous build if (licensesOutputFile.exists()) { loadLicenseInfo(configuredDepLicensesMap, licensesOutputFile, true); } // Manually configured license info, loaded second to override previously loaded info if (licensesConfigFile.exists()) { loadLicenseInfo(configuredDepLicensesMap, licensesConfigFile, false); } Set<MavenProject> dependencies = getDependencies(); // The resulting list of licenses after dependency resolution List<ProjectLicenseInfo> depProjectLicenses = new ArrayList<ProjectLicenseInfo>(); for (MavenProject project : dependencies) { Artifact artifact = project.getArtifact(); getLog().debug("Checking licenses for project " + artifact); String artifactProjectId = getArtifactProjectId(artifact); ProjectLicenseInfo depProject; if (configuredDepLicensesMap.containsKey(artifactProjectId)) { depProject = configuredDepLicensesMap.get(artifactProjectId); depProject.setVersion(artifact.getVersion()); } else { depProject = createDependencyProject(project); } downloadLicenses(depProject); depProjectLicenses.add(depProject); } try { LicenseSummaryWriter.writeLicenseSummary(depProjectLicenses, licensesOutputFile); } catch (Exception e) { throw new MojoExecutionException("Unable to write license summary file: " + licensesOutputFile, e); } } // ---------------------------------------------------------------------- // MavenProjectDependenciesConfigurator Implementation // ---------------------------------------------------------------------- /** * {@inheritDoc} */ public boolean isIncludeTransitiveDependencies() { return includeTransitiveDependencies; } /** * {@inheritDoc} */ public List<String> getExcludedScopes() { String[] split = excludedScopes == null ? new String[0] : excludedScopes.split(","); return Arrays.asList(split); } public void setExcludedScopes(String excludedScopes) { this.excludedScopes = excludedScopes; } /** * {@inheritDoc} */ public List<String> getIncludedScopes() { String[] split = includedScopes == null ? new String[0] : includedScopes.split(","); return Arrays.asList(split); } // not used at the moment /** * {@inheritDoc} */ public String getIncludedArtifacts() { return null; } // not used at the moment /** * {@inheritDoc} */ public String getIncludedGroups() { return null; } // not used at the moment /** * {@inheritDoc} */ public String getExcludedGroups() { return null; } // not used at the moment /** * {@inheritDoc} */ public String getExcludedArtifacts() { return null; } /** * {@inheritDoc} */ public boolean isVerbose() { return getLog().isDebugEnabled(); } // ---------------------------------------------------------------------- // Private Methods // ---------------------------------------------------------------------- private void initDirectories() throws MojoExecutionException { try { FileUtil.createDirectoryIfNecessary(licensesOutputDirectory); FileUtil.createDirectoryIfNecessary(licensesOutputFile.getParentFile()); } catch (IOException e) { throw new MojoExecutionException("Unable to create a directory...", e); } } private void initProxy() throws MojoExecutionException { Proxy proxyToUse = null; for (Proxy proxy : proxies) { if (proxy.isActive() && "http".equals(proxy.getProtocol())) { // found our proxy proxyToUse = proxy; break; } } if (proxyToUse != null) { System.getProperties().put("proxySet", "true"); System.setProperty("proxyHost", proxyToUse.getHost()); System.setProperty("proxyPort", String.valueOf(proxyToUse.getPort())); if (proxyToUse.getNonProxyHosts() != null) { System.setProperty("nonProxyHosts", proxyToUse.getNonProxyHosts()); } if (proxyToUse.getUsername() != null) { String loginPassword = proxyToUse.getUsername() + ":" + proxyToUse.getPassword(); proxyLoginPasswordEncoded = new String(Base64.encodeBase64(loginPassword.getBytes())); } } } /** * Load the license information contained in a file if it exists. Will overwrite existing license information in the * map for dependencies with the same id. If the config file does not exist, the method does nothing. * * @param configuredDepLicensesMap A map between the dependencyId and the license info * @param licenseConfigFile The license configuration file to load * @param previouslyDownloaded Whether these licenses were already downloaded * @throws MojoExecutionException if could not load license infos */ private void loadLicenseInfo(Map<String, ProjectLicenseInfo> configuredDepLicensesMap, File licenseConfigFile, boolean previouslyDownloaded) throws MojoExecutionException { FileInputStream fis = null; try { fis = new FileInputStream(licenseConfigFile); List<ProjectLicenseInfo> licensesList = LicenseSummaryReader.parseLicenseSummary(fis); for (ProjectLicenseInfo dep : licensesList) { configuredDepLicensesMap.put(dep.getId(), dep); if (previouslyDownloaded) { for (License license : dep.getLicenses()) { // Save the URL so we don't download it again downloadedLicenseURLs.add(license.getUrl()); } } } } catch (Exception e) { throw new MojoExecutionException("Unable to parse license summary output file: " + licenseConfigFile, e); } finally { FileUtil.tryClose(fis); } } /** * Returns the project ID for the artifact * * @param artifact the artifact * @return groupId:artifactId */ private String getArtifactProjectId(Artifact artifact) { return artifact.getGroupId() + ":" + artifact.getArtifactId(); } /** * Create a simple DependencyProject object containing the GAV and license info from the Maven Artifact * * @param depMavenProject the dependency maven project * @return DependencyProject with artifact and license info */ private ProjectLicenseInfo createDependencyProject(MavenProject depMavenProject) { ProjectLicenseInfo dependencyProject = new ProjectLicenseInfo(depMavenProject.getGroupId(), depMavenProject.getArtifactId(), depMavenProject.getVersion()); List<?> licenses = depMavenProject.getLicenses(); for (Object license : licenses) { dependencyProject.addLicense((License) license); } return dependencyProject; } /** * Determine filename to use for downloaded license file. The file name is based on the configured name of the * license (if available) and the remote filename of the license. * * @param depProject the project containing the license * @param license the license * @return A filename to be used for the downloaded license file * @throws MalformedURLException if the license url is malformed */ private String getLicenseFileName(ProjectLicenseInfo depProject, License license) throws MalformedURLException { String defaultExtension = ".txt"; URL licenseUrl = new URL(license.getUrl()); File licenseUrlFile = new File(licenseUrl.getPath()); String licenseFileName; if (organizeLicensesByDependencies) { licenseFileName = String .format("%s.%s%s", depProject.getGroupId(), depProject.getArtifactId(), license.getName() != null ? "_" + license.getName() : "") .toLowerCase().replaceAll("\\s+", "_"); } else { licenseFileName = licenseUrlFile.getName(); if (license.getName() != null) { licenseFileName = license.getName() + " - " + licenseUrlFile.getName(); } // Check if the file has a valid file extention int extensionIndex = licenseFileName.lastIndexOf("."); if (extensionIndex == -1 || extensionIndex > (licenseFileName.length() - 3)) { // This means it isn't a valid file extension, so append the default licenseFileName = licenseFileName + defaultExtension; } // Force lower case so we don't end up with multiple copies of the same license licenseFileName = licenseFileName.toLowerCase(); } return licenseFileName; } /** * Download the licenses associated with this project * * @param depProject The project which generated the dependency */ private void downloadLicenses(ProjectLicenseInfo depProject) { getLog().debug("Downloading license(s) for project " + depProject); List<License> licenses = depProject.getLicenses(); if (depProject.getLicenses() == null || depProject.getLicenses().isEmpty()) { if (!quiet) { getLog().warn("No license information available for: " + depProject); } return; } for (License license : licenses) { try { String licenseFileName = getLicenseFileName(depProject, license); File licenseOutputFile = new File(licensesOutputDirectory, licenseFileName); if (licenseOutputFile.exists()) { continue; } String licenseUrl = license.getUrl(); if (!downloadedLicenseURLs.contains(licenseUrl) || organizeLicensesByDependencies) { LicenseDownloader.downloadLicense(licenseUrl, proxyLoginPasswordEncoded, licenseOutputFile); downloadedLicenseURLs.add(licenseUrl); } } catch (MalformedURLException e) { if (!quiet) { getLog().warn("POM for dependency " + depProject.toString() + " has an invalid license URL: " + license.getUrl()); } } catch (FileNotFoundException e) { if (!quiet) { getLog().warn("POM for dependency " + depProject.toString() + " has a license URL that returns file not found: " + license.getUrl()); } } catch (IOException e) { getLog().warn("Unable to retrieve license for dependency: " + depProject.toString()); getLog().warn(license.getUrl()); getLog().warn(e.getMessage()); } } } }