From 84e6311b2f886addfe730896168fb400b9083570 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Fri, 1 Nov 2024 17:21:25 -0700 Subject: [PATCH 01/10] Updates to support SPDX version 3 NOTE: changes are not complete - this commit includes code that breaks the compilation. This is just an intermediate checking to save progress --- pom.xml | 11 +- src/main/java/org/spdx/maven/Annotation.java | 3 - .../java/org/spdx/maven/CreateSpdxMojo.java | 187 ++++------ .../java/org/spdx/maven/OutputFormat.java | 14 +- .../org/spdx/maven/PathSpecificSpdxInfo.java | 23 +- .../utils/AbstractDependencyInformation.java | 42 +++ .../maven/utils/AbstractDocumentBuilder.java | 150 ++++++++ .../spdx/maven/utils/ILicenseContainer.java | 16 + .../maven/utils/LicenseManagerException.java | 2 +- .../maven/utils/MavenToSpdxLicenseMapper.java | 2 +- .../utils/SpdxDefaultFileInformation.java | 22 +- .../utils/SpdxDependencyInformation.java | 4 +- .../spdx/maven/utils/SpdxDocumentBuilder.java | 6 +- .../spdx/maven/utils/SpdxFileCollector.java | 26 +- .../maven/utils/SpdxProjectInformation.java | 76 +++-- .../utils/SpdxV2DependencyInformation.java | 42 +++ .../maven/utils/SpdxV2DocumentBuilder.java | 149 ++++++++ ...Manager.java => SpdxV2LicenseManager.java} | 37 +- .../utils/SpdxV3DependencyInformation.java | 42 +++ .../maven/utils/SpdxV3DocumentBuilder.java | 158 +++++++++ .../maven/utils/SpdxV3LicenseManager.java | 319 ++++++++++++++++++ .../spdx/maven/utils/TestLicenseManager.java | 22 +- 22 files changed, 1106 insertions(+), 247 deletions(-) create mode 100644 src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java create mode 100644 src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java create mode 100644 src/main/java/org/spdx/maven/utils/ILicenseContainer.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java rename src/main/java/org/spdx/maven/utils/{LicenseManager.java => SpdxV2LicenseManager.java} (90%) create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java diff --git a/pom.xml b/pom.xml index 9060c6b..6868ef3 100644 --- a/pom.xml +++ b/pom.xml @@ -98,17 +98,17 @@ org.spdx java-spdx-library - 1.1.12 + 2.0.0-Alpha org.spdx spdx-rdf-store - 1.1.9 + 2.0.0-Alpha org.spdx spdx-jackson-store - 1.1.9 + 2.0.0-Alpha @@ -147,6 +147,11 @@ 1.1.0 test + + org.spdx + spdx-v3jsonld-store + 0.1.0-Alpha + diff --git a/src/main/java/org/spdx/maven/Annotation.java b/src/main/java/org/spdx/maven/Annotation.java index 6ed1564..2f6052c 100644 --- a/src/main/java/org/spdx/maven/Annotation.java +++ b/src/main/java/org/spdx/maven/Annotation.java @@ -16,9 +16,6 @@ package org.spdx.maven; import org.apache.maven.plugin.MojoExecutionException; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.enumerations.AnnotationType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index afda541..3a4e3a2 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -37,26 +37,20 @@ import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException; import org.apache.maven.shared.dependency.graph.DependencyNode; import org.apache.maven.shared.model.fileset.FileSet; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.Checksum; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.enumerations.ChecksumAlgorithm; -import org.spdx.library.model.enumerations.Purpose; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.InvalidLicenseStringException; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.SpdxNoAssertionLicense; - -import org.spdx.maven.utils.LicenseManagerException; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.maven.utils.LicenseMapperException; import org.spdx.maven.utils.SpdxBuilderException; import org.spdx.maven.utils.SpdxCollectionException; import org.spdx.maven.utils.SpdxDefaultFileInformation; -import org.spdx.maven.utils.SpdxDependencyInformation; -import org.spdx.maven.utils.SpdxDocumentBuilder; +import org.spdx.maven.utils.AbstractDependencyInformation; +import org.spdx.maven.utils.AbstractDocumentBuilder; import org.spdx.maven.utils.SpdxFileCollector; import org.spdx.maven.utils.SpdxProjectInformation; +import org.spdx.maven.utils.SpdxV2DependencyInformation; +import org.spdx.maven.utils.SpdxV2DocumentBuilder; +import org.spdx.maven.utils.SpdxV3DependencyInformation; +import org.spdx.maven.utils.SpdxV3DocumentBuilder; import java.io.File; import java.net.URI; @@ -509,8 +503,8 @@ public void execute() throws MojoExecutionException getLog().info( "Creating SPDX File " + spdxFile.getPath() ); - SpdxDocumentBuilder builder = initSpdxDocumentBuilder( outputFormatEnum ); - SpdxDocument spdxDoc = builder.getSpdxDoc(); + AbstractDocumentBuilder builder = initSpdxDocumentBuilder( outputFormatEnum ); + CoreModelObject spdxDoc = builder.getSpdxDoc(); // fill project information try @@ -525,8 +519,8 @@ public void execute() throws MojoExecutionException } // collect file-level information - SpdxDefaultFileInformation defaultFileInformation = getDefaultFileInfoFromParameters( spdxDoc ); - HashMap pathSpecificInformation = getPathSpecificInfoFromParameters( defaultFileInformation, spdxDoc ); + SpdxDefaultFileInformation defaultFileInformation = getDefaultFileInfoFromParameters(); + HashMap pathSpecificInformation = getPathSpecificInfoFromParameters( defaultFileInformation ); List sources = toFileSet( mavenProject.getCompileSourceRoots(), mavenProject.getResources() ); sources.addAll( toFileSet( mavenProject.getTestCompileSourceRoots(), null ) ); // TODO: why not test resources given source resources are taken into account? @@ -544,7 +538,7 @@ public void execute() throws MojoExecutionException // add dependencies information try { - SpdxDependencyInformation dependencyInformation = getSpdxDependencyInformation( builder ); + AbstractDependencyInformation dependencyInformation = getSpdxDependencyInformation( builder, outputFormatEnum ); builder.addDependencyInformation( dependencyInformation ); } @@ -603,7 +597,7 @@ private OutputFormat prepareOutput() return outputFormatEnum; } - private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEnum ) + private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEnum ) throws MojoExecutionException { if ( onlyUseLocalLicenses ) @@ -614,7 +608,7 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn defaultLicenseInformationInFile = defaultFileConcludedLicense; } - SpdxDocumentBuilder builder; + AbstractDocumentBuilder builder; try { if ( spdxDocumentNamespace.startsWith( "http://spdx.org/spdxpackages/" )) { @@ -622,8 +616,16 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn spdxDocumentNamespace = spdxDocumentNamespace.replace( " ", "%20" ); } URI namespaceUri = new URI( spdxDocumentNamespace ); - builder = new SpdxDocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, - this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); + if ( OutputFormat.JSON_LD.equals( outputFormatEnum ) ) { + builder = new SpdxV3DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, + this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); + } + else + { + builder = new SpdxV2DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, + this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); + } + } catch ( SpdxBuilderException e ) { @@ -659,12 +661,22 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn * @throws LicenseMapperException * @throws InvalidSPDXAnalysisException */ - private SpdxDependencyInformation getSpdxDependencyInformation( SpdxDocumentBuilder builder ) + private AbstractDependencyInformation getSpdxDependencyInformation( AbstractDocumentBuilder builder, OutputFormat outputFormatEnum ) throws LicenseMapperException, InvalidSPDXAnalysisException, DependencyGraphBuilderException { - SpdxDependencyInformation retval = new SpdxDependencyInformation( builder.getLicenseManager(), builder.getSpdxDoc(), - createExternalRefs, generatePurls, useArtifactID, - includeTransitiveDependencies ); + AbstractDependencyInformation retval; + if ( builder instanceof SpdxV3DocumentBuilder ) + { + retval = new SpdxV3DependencyInformation( (SpdxV3DocumentBuilder)builder, createExternalRefs, + generatePurls, useArtifactID, + includeTransitiveDependencies ); + } + else + { + retval = new SpdxV2DependencyInformation( (SpdxV2DocumentBuilder)builder, + createExternalRefs, generatePurls, useArtifactID, + includeTransitiveDependencies ); + } if ( session != null ) { @@ -699,8 +711,7 @@ private void logFileSpecificInfo( HashMap fi * @return * @throws MojoExecutionException */ - private HashMap getPathSpecificInfoFromParameters( SpdxDefaultFileInformation projectDefault, - SpdxDocument spdxDoc ) throws MojoExecutionException + private HashMap getPathSpecificInfoFromParameters( SpdxDefaultFileInformation projectDefault ) throws MojoExecutionException { HashMap retval = new HashMap<>(); if ( this.pathsWithSpecificSpdxInfo != null ) @@ -708,15 +719,7 @@ private HashMap getPathSpecificInfoFromParam for ( PathSpecificSpdxInfo spdxInfo : this.pathsWithSpecificSpdxInfo ) { SpdxDefaultFileInformation value = null; - try - { - value = spdxInfo.getDefaultFileInformation( projectDefault, spdxDoc ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new MojoExecutionException( - "Invalid license string used in the path specific SPDX information for file " + spdxInfo.getPath(), e ); - } + value = spdxInfo.getDefaultFileInformation( projectDefault ); if ( retval.containsKey( spdxInfo.getPath() ) ) { getLog().warn( "Multiple file path specific SPDX data for " + spdxInfo.getPath() ); @@ -791,42 +794,15 @@ private void logIncludedDirectories( List includedDirectories ) * @return default file information from the plugin parameters * @throws MojoExecutionException */ - private SpdxDefaultFileInformation getDefaultFileInfoFromParameters( SpdxDocument spdxDoc ) throws MojoExecutionException + private SpdxDefaultFileInformation getDefaultFileInfoFromParameters() throws MojoExecutionException { SpdxDefaultFileInformation retval; - try - { - retval = new SpdxDefaultFileInformation(); - } - catch ( InvalidSPDXAnalysisException e1 ) - { - throw new MojoExecutionException( "Error getting default file information", e1 ); - } + retval = new SpdxDefaultFileInformation(); retval.setComment( defaultFileComment ); - AnyLicenseInfo concludedLicense = null; - try - { - concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( defaultFileConcludedLicense.trim(), - spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); - } - catch ( InvalidLicenseStringException e ) - { - throw new MojoExecutionException( "Invalid default file concluded license", e ); - } - retval.setConcludedLicense( concludedLicense ); + retval.setConcludedLicense( defaultFileConcludedLicense.trim() ); retval.setContributors( defaultFileContributors ); retval.setCopyright( defaultFileCopyright ); - AnyLicenseInfo declaredLicense = null; - try - { - declaredLicense = LicenseInfoFactory.parseSPDXLicenseString( defaultLicenseInformationInFile.trim(), - spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); - } - catch ( InvalidLicenseStringException e ) - { - throw new MojoExecutionException( "Invalid default file declared license", e ); - } - retval.setDeclaredLicense( declaredLicense ); + retval.setDeclaredLicense( defaultLicenseInformationInFile.trim() ); retval.setLicenseComment( defaultFileLicenseComment ); retval.setNotice( defaultFileNotice ); return retval; @@ -848,60 +824,31 @@ private SpdxDefaultFileInformation getDefaultFileInfoFromParameters( SpdxDocumen * @return * @throws MojoExecutionException */ - private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBuilder builder ) throws MojoExecutionException, InvalidSPDXAnalysisException + private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumentBuilder builder ) throws MojoExecutionException, InvalidSPDXAnalysisException { - SpdxDocument spdxDoc = builder.getSpdxDoc(); SpdxProjectInformation retval = new SpdxProjectInformation(); if ( this.documentComment != null ) { retval.setDocumentComment( this.documentComment ); } - AnyLicenseInfo declaredLicense = null; + String declaredLicense = null; if ( this.licenseDeclared == null ) { List mavenLicenses = mavenProject.getLicenses(); - try - { - declaredLicense = builder.getLicenseManager().mavenLicenseListToSpdxLicense( mavenLicenses ); - } - catch ( LicenseManagerException e ) - { - getLog().warn( "Unable to map maven licenses to a declared license. Using NOASSERTION" ); - declaredLicense = new SpdxNoAssertionLicense(); - } + declaredLicense = builder.mavenLicenseListToSpdxLicenseExpression( mavenLicenses ); } else { - try - { - declaredLicense = LicenseInfoFactory.parseSPDXLicenseString( this.licenseDeclared.trim(), - spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), - spdxDoc.getCopyManager()); - } - catch ( InvalidLicenseStringException e ) - { - throw new MojoExecutionException( "Invalid declared license: " + licenseDeclared.trim(), e ); - } + declaredLicense = this.licenseDeclared.trim(); } - AnyLicenseInfo concludedLicense = null; + String concludedLicense = null; if ( this.licenseConcluded == null ) { concludedLicense = declaredLicense; } else { - try - { - concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( this.licenseConcluded.trim(), - spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), - spdxDoc.getCopyManager() ); - } - catch ( InvalidLicenseStringException e ) - { - throw new MojoExecutionException( "Invalid concluded license: " + licenseConcluded.trim(), e ); - } + concludedLicense = this.licenseConcluded.trim(); } retval.setConcludedLicense( concludedLicense ); retval.setCreatorComment( this.creatorComment ); @@ -952,14 +899,14 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBui packageFile = new File(mainArtifact.getFile().getParent() + File.separator + packageFileName); } - Set checksums = null; + Set checksums = null; if ( packageFile != null && packageFile.exists() ) { try { getLog().debug( "Generating checksum for file "+packageFile.getAbsolutePath() ); - Set algorithms = getChecksumAlgorithms(); - checksums = SpdxFileCollector.generateChecksum( packageFile, algorithms, spdxDoc ); + Set algorithms = getChecksumAlgorithms(); + checksums = SpdxFileCollector.generateChecksum( packageFile, algorithms, builder ); } catch ( SpdxCollectionException | InvalidSPDXAnalysisException e ) { @@ -989,9 +936,9 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBui retval.setDocumentAnnotations( this.documentAnnotations ); retval.setPackageAnnotations( this.packageAnnotations ); retval.setExternalRefs( this.externalReferences ); - - final Packaging packaging = Packaging.valueOfPackaging( mavenProject.getPackaging() ); - retval.setPrimaryPurpose(packaging != null ? packaging.getPurpose() : Purpose.LIBRARY); + + final Packaging packaging = Packaging.valueOfPackaging( mavenProject.getPackaging() ); + retval.setPackaging( packaging != null ? packaging : Packaging.JAR ); return retval; } @@ -1043,27 +990,19 @@ private static List toFileSet( List roots, List resou } /** - * Map user input algorithms to Checksum.ChecksumAlgorithm values. {@code ChecksumAlgorithm.checksumAlgorithm_sha1} - * is always added to the set because it is mandatory to include the SHA1 checksum. A warning is logged for invalid - * user input. + * Map user input algorithms to Checksum.ChecksumAlgorithm values. {@code SHA1} + * is always added to the set because it is mandatory to include the SHA1 checksum. * @return set of algorithms to calculate checksum with */ - private Set getChecksumAlgorithms() + private Set getChecksumAlgorithms() { - Set algorithms = new HashSet<>(); - algorithms.add( ChecksumAlgorithm.SHA1 ); + Set algorithms = new HashSet<>(); + algorithms.add( "SHA1" ); if ( checksumAlgorithms != null ) { for ( String checksumAlgorithm : checksumAlgorithms ) { - try - { - algorithms.add( ChecksumAlgorithm.valueOf( checksumAlgorithm.toUpperCase() ) ); - } - catch (final IllegalArgumentException iae) - { - getLog().warn( "Ignoring unsupported checksum algorithm: " + checksumAlgorithm ); - } + algorithms.add( checksumAlgorithm ); } } return algorithms; diff --git a/src/main/java/org/spdx/maven/OutputFormat.java b/src/main/java/org/spdx/maven/OutputFormat.java index 490ff4b..050a622 100644 --- a/src/main/java/org/spdx/maven/OutputFormat.java +++ b/src/main/java/org/spdx/maven/OutputFormat.java @@ -25,7 +25,8 @@ public enum OutputFormat { RDF_XML("RDF/XML", "spdx.rdf.xml", ".rdf.xml"), - JSON("JSON", "spdx.json", ".json"); + JSON("JSON", "spdx.json", ".json"), + JSON_LD("JSON-LD", "spdx.json-ld.json", ".json-ld.json"); private final String value; private final String artifactType; @@ -45,7 +46,12 @@ public static OutputFormat getOutputFormat(final String format, final File file) { if (file != null) { - return file.getName().toLowerCase().endsWith(".rdf.xml") ? RDF_XML : JSON; + String fileName = file.getName().toLowerCase(); + if (fileName.endsWith(".rdf.xml")) + { + return RDF_XML; + } + return file.getName().toLowerCase().endsWith(".json-ld.json") ? JSON_LD : JSON; } throw new IllegalArgumentException("Could not determine output file"); } @@ -58,6 +64,10 @@ else if (JSON.value.equals(upperCaseFormat)) { return JSON; } + else if (JSON_LD.value.equals(upperCaseFormat)) + { + return JSON_LD; + } throw new IllegalArgumentException("Invalid SPDX output format: " + format); } diff --git a/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java b/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java index f8956ad..06fe049 100644 --- a/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java +++ b/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java @@ -16,12 +16,6 @@ package org.spdx.maven; import java.util.List; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; - import org.spdx.maven.utils.SpdxDefaultFileInformation; /** @@ -112,8 +106,7 @@ public PathSpecificSpdxInfo() * @return default file information to be used with this file path * @throws InvalidSPDXAnalysisException */ - public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInformation defaults, - SpdxDocument spdxDoc ) throws InvalidSPDXAnalysisException + public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInformation defaults ) { SpdxDefaultFileInformation retval = new SpdxDefaultFileInformation(); if ( this.fileComment != null ) @@ -126,12 +119,7 @@ public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInfo } if ( this.fileConcludedLicense != null ) { - AnyLicenseInfo concludedLicense = null; - concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( fileConcludedLicense.trim(), - spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), - spdxDoc.getCopyManager() ); - retval.setConcludedLicense( concludedLicense ); + retval.setConcludedLicense( this.fileConcludedLicense ); } else { @@ -171,12 +159,7 @@ public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInfo } if ( this.licenseInformationInFile != null ) { - AnyLicenseInfo declaredLicense = null; - declaredLicense = LicenseInfoFactory.parseSPDXLicenseString( licenseInformationInFile.trim(), - spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), - spdxDoc.getCopyManager() ); - retval.setDeclaredLicense( declaredLicense ); + retval.setDeclaredLicense( licenseInformationInFile.trim() ); } else { diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java new file mode 100644 index 0000000..5fa6dae --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java @@ -0,0 +1,42 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.shared.dependency.graph.DependencyNode; + +/** + * Contains information about package dependencies collected from the Maven dependencies. + * + * Subclasses implement dependency information specific to SPDX spec major versions + * + * @author Gary O'Neall + * + */ +public abstract class AbstractDependencyInformation +{ + + /** + * + */ + public AbstractDependencyInformation() + { + // TODO Auto-generated constructor stub + } + + /** + * @param mavenProjectBuilder + * @param session + * @param mavenProject + * @param parentNode + * @param projectPackage + */ + public abstract void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, + MavenProject mavenProject, DependencyNode parentNode, + Object projectPackage ); + +} diff --git a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java new file mode 100644 index 0000000..9d00b74 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java @@ -0,0 +1,150 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import org.apache.maven.model.License; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.model.fileset.FileSet; +import org.spdx.core.CoreModelObject; +import org.spdx.library.ModelCopyManager; +import org.spdx.maven.NonStandardLicense; +import org.spdx.maven.OutputFormat; +import org.spdx.storage.IModelStore; + +/** + * Abstract class to create SPDX documents. + * + * Subclasses of this class implement specific SPDX specification versions of the document + * + * @author Gary O'Neall + */ +public abstract class AbstractDocumentBuilder +{ + + protected MavenProject project; + protected boolean generatePurls; + protected File spdxFile; + protected OutputFormat outputFormatEnum; + protected boolean matchLicensesOnCrossReferenceUrls; + protected IModelStore modelStore; + protected ModelCopyManager copyManager; + + /** + * + */ + public AbstractDocumentBuilder() + { + // TODO Auto-generated constructor stub + } + + /** + * @param project Maven Project + * @param generatePurls If true, generated Package URLs for all package references + * @param spdxFile File to store the SPDX document results + * @param outputFormatEnum File format for the SPDX file + * @throws SpdxBuilderException On errors building the document + */ + public AbstractDocumentBuilder( MavenProject project, boolean generatePurls, File spdxFile, + OutputFormat outputFormatEnum ) throws SpdxBuilderException + { + this.project = project; + this.generatePurls = generatePurls; + this.spdxFile = spdxFile; + this.outputFormatEnum = outputFormatEnum; + copyManager = new ModelCopyManager(); + + // Handle the SPDX file + if ( !spdxFile.exists() ) + { + File parentDir = spdxFile.getParentFile(); + if ( parentDir != null && !parentDir.exists() ) + { + if ( !parentDir.mkdirs() ) + { + throw new SpdxBuilderException( "Unable to create directories for SPDX file" ); + } + } + + try + { + if ( !spdxFile.createNewFile() ) + { + throw new SpdxBuilderException( "Unable to create the SPDX file" ); + } + } + catch ( IOException e ) + { + throw new SpdxBuilderException( "IO error creating the SPDX file", e ); + } + } + if ( !spdxFile.canWrite() ) + { + throw new SpdxBuilderException( "Unable to write to SPDX file - check permissions: " + spdxFile.getPath() ); + } + + } + + /** + * @return + */ + public abstract CoreModelObject getSpdxDoc(); + + /** + * @param projectInformation + */ + public abstract void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ); + + /** + * @param sources + * @param absolutePath + * @param defaultFileInformation + * @param pathSpecificInformation + * @param checksumAlgorithms + */ + public abstract void collectSpdxFileInformation( List sources, String absolutePath, + SpdxDefaultFileInformation defaultFileInformation, + HashMap pathSpecificInformation, + Set checksumAlgorithms ); + + /** + * @param dependencyInformation + */ + public abstract void addDependencyInformation( AbstractDependencyInformation dependencyInformation ); + + /** + * + */ + public abstract void saveSpdxDocumentToFile(); + + /** + * @param nonStandardLicenses + */ + public abstract void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException; + + /** + * @return + */ + public abstract Object getProjectPackage(); + + /** + * @param algorithm + * @param checksum + * @return + */ + public abstract Object createChecksum( String algorithm, String checksum ); + + /** + * @param mavenLicenses + * @return + */ + public abstract String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ); + +} diff --git a/src/main/java/org/spdx/maven/utils/ILicenseContainer.java b/src/main/java/org/spdx/maven/utils/ILicenseContainer.java new file mode 100644 index 0000000..0e9d493 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/ILicenseContainer.java @@ -0,0 +1,16 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +/** + * Interface for a container which contains extracted / non-listed licenses + * + * @author Gary O'Neall + * + */ +public interface ILicenseContainer +{ + +} diff --git a/src/main/java/org/spdx/maven/utils/LicenseManagerException.java b/src/main/java/org/spdx/maven/utils/LicenseManagerException.java index 16136a6..0e576ac 100644 --- a/src/main/java/org/spdx/maven/utils/LicenseManagerException.java +++ b/src/main/java/org/spdx/maven/utils/LicenseManagerException.java @@ -16,7 +16,7 @@ package org.spdx.maven.utils; /** - * Exceptions related to the LicenseManager + * Exceptions related to the SpdxV2LicenseManager * * @author Gary O'Neall */ diff --git a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java index 6847044..f3001e8 100644 --- a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java +++ b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java @@ -87,7 +87,7 @@ private MavenToSpdxLicenseMapper() throws LicenseMapperException if ( is == null ) { // use the cached version - is = LicenseManager.class.getClassLoader().getResourceAsStream( LISTED_LICENSE_JSON_PATH ); + is = SpdxV2LicenseManager.class.getClassLoader().getResourceAsStream( LISTED_LICENSE_JSON_PATH ); } try (BufferedReader reader = new BufferedReader( new InputStreamReader( is, Charset.defaultCharset() ) )) diff --git a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java index d726834..625380c 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java @@ -18,10 +18,6 @@ import java.util.ArrayList; import java.util.List; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.SpdxNoAssertionLicense; - import org.spdx.maven.SnippetInfo; import org.slf4j.Logger; @@ -36,27 +32,27 @@ public class SpdxDefaultFileInformation { private static final Logger LOG = LoggerFactory.getLogger( SpdxDefaultFileInformation.class ); - private AnyLicenseInfo declaredLicense; + private String declaredLicense; private String copyright = "NOASSERTION"; private String notice = ""; private String comment = ""; private String[] contributors = new String[0]; - private AnyLicenseInfo concludedLicense; + private String concludedLicense; private String licenseComment = ""; private List snippets = new ArrayList<>(); - public SpdxDefaultFileInformation() throws InvalidSPDXAnalysisException + public SpdxDefaultFileInformation() { - declaredLicense = new SpdxNoAssertionLicense(); - concludedLicense = new SpdxNoAssertionLicense(); + declaredLicense = "NOASSERTION"; + concludedLicense = "NOASSERTION"; } - public AnyLicenseInfo getDeclaredLicense() + public String getDeclaredLicense() { return this.declaredLicense; } - public void setDeclaredLicense( AnyLicenseInfo license ) + public void setDeclaredLicense( String license ) { this.declaredLicense = license; } @@ -101,12 +97,12 @@ public void setContributors( String[] contributors ) this.contributors = contributors; } - public AnyLicenseInfo getConcludedLicense() + public String getConcludedLicense() { return this.concludedLicense; } - public void setConcludedLicense( AnyLicenseInfo license ) + public void setConcludedLicense( String license ) { this.concludedLicense = license; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java index dd77eea..3a027f2 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java @@ -96,7 +96,7 @@ public class SpdxDependencyInformation */ private Map externalDocuments = new HashMap<>(); private List documentAnnotations = new ArrayList<>(); - private LicenseManager licenseManager; + private SpdxV2LicenseManager licenseManager; private SpdxDocument spdxDoc; private boolean createExternalRefs = false; private boolean generatePurls = false; @@ -106,7 +106,7 @@ public class SpdxDependencyInformation /** */ - public SpdxDependencyInformation( LicenseManager licenseManager, + public SpdxDependencyInformation( SpdxV2LicenseManager licenseManager, SpdxDocument spdxDoc, boolean createExternalRefs, boolean generatePurls, boolean useArtifactID, boolean includeTransitiveDependencies ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java index 81b652b..535c6a4 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java @@ -86,7 +86,7 @@ public class SpdxDocumentBuilder private boolean generatePurls; private SpdxDocument spdxDoc; private SpdxPackage projectPackage; - private LicenseManager licenseManager; + private SpdxV2LicenseManager licenseManager; private File spdxFile; private ISerializableModelStore modelStore; @@ -156,7 +156,7 @@ public SpdxDocumentBuilder( MavenProject project, boolean generatePurls, File sp } // process the licenses - licenseManager = new LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + licenseManager = new SpdxV2LicenseManager( spdxDoc, useStdLicenseSourceUrls ); } /** @@ -520,7 +520,7 @@ public void collectSpdxFileInformation( List sources, String baseDir, } } - public LicenseManager getLicenseManager() + public SpdxV2LicenseManager getLicenseManager() { return this.licenseManager; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java index 038eeb4..45f7876 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java @@ -27,20 +27,8 @@ import org.apache.maven.shared.model.fileset.FileSet; import org.apache.maven.shared.model.fileset.util.FileSetManager; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.Checksum; -import org.spdx.library.model.Relationship; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxFile; -import org.spdx.library.model.SpdxPackage; -import org.spdx.library.model.SpdxPackageVerificationCode; -import org.spdx.library.model.SpdxSnippet; -import org.spdx.library.model.enumerations.ChecksumAlgorithm; -import org.spdx.library.model.enumerations.FileType; -import org.spdx.library.model.enumerations.RelationshipType; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.InvalidLicenseStringException; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.maven.SnippetInfo; import org.spdx.storage.IModelStore.IdType; @@ -70,7 +58,7 @@ public class SpdxFileCollector loadFileExtensionConstants(); } - static final Map checksumAlgorithms = new HashMap<>(); + static final Map checksumAlgorithms = new HashMap<>(); static { @@ -649,8 +637,8 @@ public static String generateSha1( File file, SpdxDocument spdxDoc ) throws Spdx * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read * @throws InvalidSPDXAnalysisException */ - public static Set generateChecksum( File file, Set algorithms, - SpdxDocument spdxDoc ) throws SpdxCollectionException, InvalidSPDXAnalysisException + public static Set generateChecksum( File file, Set algorithms, + AbstractDocumentBuilder builder ) throws SpdxCollectionException, InvalidSPDXAnalysisException { Set checksums = new HashSet<>(); @@ -664,7 +652,7 @@ public static Set generateChecksum( File file, Set throw new SpdxCollectionException( "IO error while calculating checksums.", e ); } - for ( ChecksumAlgorithm algorithm : algorithms ) + for ( String algorithm : algorithms ) { String checksumAlgorithm = checksumAlgorithms.get( algorithm ); @@ -680,7 +668,7 @@ public static Set generateChecksum( File file, Set digest.update( buffer ); String checksum = convertChecksumToString( digest.digest() ); - checksums.add( spdxDoc.createChecksum( algorithm, checksum ) ); + checksums.add( builder.createChecksum( algorithm, checksum ) ); } return checksums; diff --git a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java index 41bc574..5b05a6d 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java @@ -19,20 +19,16 @@ import java.net.URISyntaxException; import java.util.Set; +import org.apache.jena.query.ModelStore; import org.apache.maven.plugin.MojoExecutionException; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.Checksum; -import org.spdx.library.model.ExternalRef; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.enumerations.Purpose; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.SpdxNoAssertionLicense; +import org.spdx.core.CoreModelObject; import org.spdx.library.referencetype.ListedReferenceTypes; import org.spdx.maven.Annotation; import org.spdx.maven.ExternalReference; - +import org.spdx.maven.Packaging; +import org.spdx.storage.IModelStore; +import org.spdx.storage.PropertyDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,8 +43,8 @@ public class SpdxProjectInformation private String[] creators = new String[0]; private String creatorComment = ""; - private AnyLicenseInfo concludedLicense; - private AnyLicenseInfo declaredLicense; + private String concludedLicense; + private String declaredLicense; private String description; private String downloadUrl; private String homePage; @@ -65,29 +61,31 @@ public class SpdxProjectInformation private Annotation[] packageAnnotations; private Annotation[] documentAnnotations; private ExternalReference[] externalRefs; - private Set checksums; - private Purpose primaryPurpose; + private Set checksums; + private Packaging packaging; + + /** - * @return the primaryPurpose + * @return the packaging */ - public Purpose getPrimaryPurpose() + public Packaging getPackaging() { - return primaryPurpose; + return packaging; } /** - * @param primaryPurpose the primaryPurpose to set + * @param packaging the packaging to set */ - public void setPrimaryPurpose( Purpose primaryPurpose ) + public void setPackaging( Packaging packaging ) { - this.primaryPurpose = primaryPurpose; + this.packaging = packaging; } - public SpdxProjectInformation () throws InvalidSPDXAnalysisException + public SpdxProjectInformation () { - this.concludedLicense = new SpdxNoAssertionLicense(); - this.declaredLicense = new SpdxNoAssertionLicense(); + this.concludedLicense = "NOASSERTION"; + this.declaredLicense = "NOASSERTION"; } /** @@ -109,7 +107,7 @@ public void setDocumentComment( String documentComment ) /** * @return checksums for the project */ - public Set getChecksums() + public Set getChecksums() { return checksums; } @@ -117,7 +115,7 @@ public Set getChecksums() /** * @param checksums the checksums to set for the project */ - public void setChecksums( Set checksums ) + public void setChecksums( Set checksums ) { this.checksums = checksums; } @@ -125,7 +123,7 @@ public void setChecksums( Set checksums ) /** * @return the concludedLicense */ - public AnyLicenseInfo getConcludedLicense() + public String getConcludedLicense() { return concludedLicense; } @@ -133,7 +131,7 @@ public AnyLicenseInfo getConcludedLicense() /** * @param concludedLicense the concludedLicense to set */ - public void setConcludedLicense( AnyLicenseInfo concludedLicense ) + public void setConcludedLicense( String concludedLicense ) { this.concludedLicense = concludedLicense; } @@ -141,7 +139,7 @@ public void setConcludedLicense( AnyLicenseInfo concludedLicense ) /** * @return the declaredLicense */ - public AnyLicenseInfo getDeclaredLicense() + public String getDeclaredLicense() { return declaredLicense; } @@ -149,7 +147,7 @@ public AnyLicenseInfo getDeclaredLicense() /** * @param declaredLicense the declaredLicense to set */ - public void setDeclaredLicense( AnyLicenseInfo declaredLicense ) + public void setDeclaredLicense( String declaredLicense ) { this.declaredLicense = declaredLicense; } @@ -339,6 +337,28 @@ public void setName( String name ) { this.name = name; } + + /** + * Log information on all fields - typically used for debugging + */ + public void logInfo( CoreModelObject modelObject ) + { + if ( !LOG.isDebugEnabled() ) { + return; + } + IModelStore store = modelObject.getModelStore(); + String objectUri = modelObject.getObjectUri(); + for ( PropertyDescriptor desc : store.getPropertyValueDescriptors( objectUri ) ) { + if (store.isCollectionProperty( objectUri, desc )) { + //TODO Implement + } + else + { + //TODO Implement + } + } + //TODO for SPDX V3 - log al relationships from this object + } /** * Log information on all fields - typically used for debugging diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java new file mode 100644 index 0000000..c236ed1 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java @@ -0,0 +1,42 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.shared.dependency.graph.DependencyNode; + +/** + * @author gary + * + */ +public class SpdxV2DependencyInformation + extends AbstractDependencyInformation +{ + + /** + * @param builer + * @param createExternalRefs + * @param generatePurls + * @param useArtifactID + * @param includeTransitiveDependencies + */ + public SpdxV2DependencyInformation( SpdxV2DocumentBuilder builer, boolean createExternalRefs, + boolean generatePurls, boolean useArtifactID, + boolean includeTransitiveDependencies ) + { + // TODO Auto-generated constructor stub + } + + @Override + public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, + MavenProject mavenProject, DependencyNode parentNode, Object projectPackage ) + { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java new file mode 100644 index 0000000..8c3bb87 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -0,0 +1,149 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import org.apache.maven.model.License; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.model.fileset.FileSet; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.jacksonstore.MultiFormatStore; +import org.spdx.jacksonstore.MultiFormatStore.Format; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxModelFactoryCompatV2; +import org.spdx.library.model.v2.license.ExtractedLicenseInfo; +import org.spdx.maven.NonStandardLicense; +import org.spdx.maven.OutputFormat; +import org.spdx.spdxRdfStore.RdfStore; +import org.spdx.storage.simple.InMemSpdxStore; + +/** + * Builder for SPDX Spec version 2 SPDX Documents + * + * @author Gary O'Neall + * + */ +public class SpdxV2DocumentBuilder + extends AbstractDocumentBuilder +{ + + protected SpdxDocument spdxDoc; + protected SpdxV2LicenseManager licenseManager; + + /** + * @param mavenProject Maven project + * @param generatePurls If true, generated Package URLs for all package references + * @param spdxFile File to store the SPDX document results + * @param spdxDocumentNamespace SPDX Document namespace - must be unique + * @param useStdLicenseSourceUrls if true, map any SPDX standard license source URL to license ID. Note: + * significant performance degradation + * @param outputFormatEnum + */ + public SpdxV2DocumentBuilder( MavenProject mavenProject, boolean generatePurls, File spdxFile, URI spdxDocumentNamespace, + boolean useStdLicenseSourceUrls, + OutputFormat outputFormatEnum ) throws SpdxBuilderException, LicenseMapperException + { + super( mavenProject, generatePurls, spdxFile, outputFormatEnum ); + if ( spdxDocumentNamespace == null ) + { + throw new SpdxBuilderException( "Missing namespaceUri" ); + } + + // create the SPDX document + try + { + modelStore = outputFormatEnum == OutputFormat.RDF_XML ? new RdfStore() : new MultiFormatStore( new InMemSpdxStore(), Format.JSON_PRETTY ); + copyManager = new ModelCopyManager(); + spdxDoc = SpdxModelFactoryCompatV2.createSpdxDocumentV2( modelStore, spdxDocumentNamespace.toString(), copyManager ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error creating SPDX document", e ); + } + + // process the licenses + licenseManager = new SpdxV2LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + } + + @Override + public CoreModelObject getSpdxDoc() + { + return this.spdxDoc; + } + + @Override + public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) + { + // TODO Auto-generated method stub + + } + + @Override + public void collectSpdxFileInformation( List sources, String absolutePath, + SpdxDefaultFileInformation defaultFileInformation, + HashMap pathSpecificInformation, + Set checksumAlgorithms ) + { + // TODO Auto-generated method stub + + } + + @Override + public SpdxV2LicenseManager getLicenseManager() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void addDependencyInformation( AbstractDependencyInformation dependencyInformation ) + { + // TODO Auto-generated method stub + + } + + @Override + public void saveSpdxDocumentToFile() + { + // TODO Auto-generated method stub + + } + + @Override + public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) + { + // TODO Auto-generated method stub + + } + + @Override + public Object getProjectPackage() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object createChecksum( String algorithm, String checksum ) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/org/spdx/maven/utils/LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java similarity index 90% rename from src/main/java/org/spdx/maven/utils/LicenseManager.java rename to src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java index 36953f5..eccbd51 100644 --- a/src/main/java/org/spdx/maven/utils/LicenseManager.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java @@ -21,30 +21,29 @@ import java.util.Map; import org.apache.maven.model.License; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.ExtractedLicenseInfo; -import org.spdx.library.model.license.InvalidLicenseStringException; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.SpdxListedLicense; -import org.spdx.library.model.license.SpdxNoAssertionLicense; - +import org.spdx.core.DefaultStoreNotInitialized; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.ExtractedLicenseInfo; +import org.spdx.library.model.v2.license.InvalidLicenseStringException; +import org.spdx.library.model.v2.license.SpdxListedLicense; +import org.spdx.library.model.v2.license.SpdxNoAssertionLicense; import org.spdx.maven.NonStandardLicense; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Manages the SPDX licenses for the Spdx plugin. Keeps track of any extracted licenses (added as configuration + * Manages the SPDX Spec version 2licenses for the Spdx plugin. Keeps track of any extracted licenses (added as configuration * parameters to the plugin). Maps Maven licenses to SPDX licenses. Creates a Maven license from an SPDX license. * * @author Gary O'Neall */ -public class LicenseManager +public class SpdxV2LicenseManager { - private static final Logger LOG = LoggerFactory.getLogger( LicenseManager.class ); + private static final Logger LOG = LoggerFactory.getLogger( SpdxV2LicenseManager.class ); /** * SPDX document containing the license information collected. All extracted licenses are added to the SPDX @@ -71,7 +70,7 @@ public class LicenseManager * performance degradation * @throws LicenseMapperException */ - public LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUrls ) throws LicenseMapperException + public SpdxV2LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUrls ) throws LicenseMapperException { this.spdxDoc = spdxDoc; initializeUrlMap(); @@ -205,15 +204,19 @@ public AnyLicenseInfo mavenLicenseToSpdxLicense( License mavenLicense ) throws L { try { - retval = LicenseInfoFactory.parseSPDXLicenseString( licenseId, spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), - spdxDoc.getCopyManager() ); + retval = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( licenseId, spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ); } catch ( InvalidLicenseStringException e ) { throw new LicenseManagerException( "Can not map maven license " + mavenLicense.getName() + " Invalid listed or extracted license id matching the URL " + mavenLicense.getUrl() ); } + catch ( DefaultStoreNotInitialized e ) + { + throw new LicenseManagerException( "Default model store not initialized" ); + } } return retval; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java new file mode 100644 index 0000000..316b9af --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java @@ -0,0 +1,42 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.shared.dependency.graph.DependencyNode; + +/** + * @author gary + * + */ +public class SpdxV3DependencyInformation + extends AbstractDependencyInformation +{ + + /** + * @param builder + * @param createExternalRefs + * @param generatePurls + * @param useArtifactID + * @param includeTransitiveDependencies + */ + public SpdxV3DependencyInformation( SpdxV3DocumentBuilder builder, boolean createExternalRefs, + boolean generatePurls, boolean useArtifactID, + boolean includeTransitiveDependencies ) + { + // TODO Auto-generated constructor stub + } + + @Override + public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, + MavenProject mavenProject, DependencyNode parentNode, Object projectPackage ) + { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java new file mode 100644 index 0000000..e272acd --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -0,0 +1,158 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import org.apache.maven.model.License; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.model.fileset.FileSet; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.model.v3_0_1.SpdxModelClassFactoryV3; +import org.spdx.library.model.v3_0_1.core.CreationInfo; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.software.Sbom; +import org.spdx.maven.NonStandardLicense; +import org.spdx.maven.OutputFormat; +import org.spdx.storage.simple.InMemSpdxStore; +import org.spdx.v3jsonldstore.JsonLDStore; + +/** + * Builder for SPDX Spec version 3 SBOMs + * + * @author Gary O'Neall + * + */ +public class SpdxV3DocumentBuilder + extends AbstractDocumentBuilder +{ + protected CreationInfo creationInfo; + protected Sbom sbom; + protected SpdxDocument spdxDoc; + protected SpdxV3LicenseManager licenseManager; + + /** + * @param mavenProject Maven project + * @param generatePurls If true, generated Package URLs for all package references + * @param spdxFile File to store the SPDX document results + * @param namespaceUri Namspace prefix for generated SPDX URIs document - must be unique + * @param useStdLicenseSourceUrls if true, map any SPDX standard license source URL to license ID. Note: + * significant performance degradation + * @param outputFormatEnum + */ + public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, File spdxFile, URI namespaceUri, + boolean useStdLicenseSourceUrls, + OutputFormat outputFormatEnum ) throws SpdxBuilderException, LicenseMapperException + { + super( mavenProject, generatePurls, spdxFile, outputFormatEnum ); + if ( namespaceUri == null ) + { + throw new SpdxBuilderException( "Missing namespaceUri" ); + } + + if ( !OutputFormat.JSON_LD.equals( outputFormatEnum )) { + throw new SpdxBuilderException( String.format( "Unsupported output format for SPDX spec version 3: %s", + outputFormatEnum.toString() )); + } + // create the SPDX document + try + { + modelStore = new JsonLDStore( new InMemSpdxStore() ); + String supplier = ( mavenProject.getOrganization() != null && + mavenProject.getOrganization().getName() != null + && !mavenProject.getOrganization().getName().isEmpty() ) ? mavenProject.getOrganization().getName() : project.getName() ; + + creationInfo = SpdxModelClassFactoryV3.createCreationInfo( modelStore, namespaceUri + "Agent/supplier", supplier, + copyManager); + creationInfo.getCreatedUsings().add( creationInfo.createTool( namespaceUri + "Agent/SpdxMavenPlugin" ) + .setName( "SPDX Maven Plugin" ) + .setCreationInfo( creationInfo ) + .build() ); + sbom = creationInfo.createSbom( namespaceUri + "sbom" ).build(); + spdxDoc = sbom.createSpdxDocument( namespaceUri + "/Document" ) + .addRootElement( sbom ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error creating SPDX SBOM", e ); + } + + // process the licenses + licenseManager = new SpdxV3LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + } + + @Override + public CoreModelObject getSpdxDoc() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) + { + // TODO Auto-generated method stub + + } + + @Override + public void collectSpdxFileInformation( List sources, String absolutePath, + SpdxDefaultFileInformation defaultFileInformation, + HashMap pathSpecificInformation, + Set checksumAlgorithms ) + { + // TODO Auto-generated method stub + + } + + @Override + public void addDependencyInformation( AbstractDependencyInformation dependencyInformation ) + { + // TODO Auto-generated method stub + + } + + @Override + public void saveSpdxDocumentToFile() + { + // TODO Auto-generated method stub + + } + + @Override + public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) + { + // TODO Auto-generated method stub + + } + + @Override + public Object getProjectPackage() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object createChecksum( String algorithm, String checksum ) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java new file mode 100644 index 0000000..a6fbbca --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java @@ -0,0 +1,319 @@ +/* + * Copyright 2014 Source Auditor Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.spdx.maven.utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.maven.model.License; +import org.spdx.core.DefaultStoreNotInitialized; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.model.v2.license.InvalidLicenseStringException; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.expandedlicensing.CustomLicense; +import org.spdx.library.model.v3_0_1.expandedlicensing.ListedLicense; +import org.spdx.library.model.v3_0_1.expandedlicensing.NoAssertionLicense; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.maven.NonStandardLicense; +import org.spdx.storage.IModelStore.IdType; +import org.spdx.storage.listedlicense.SpdxListedLicenseModelStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages the SPDX Spec Version 3 licenses for the Spdx plugin. Keeps track of any extracted licenses (added as configuration + * parameters to the plugin). Maps Maven licenses to SPDX licenses. Creates a Maven license from an SPDX license. + * + * @author Gary O'Neall + */ +public class SpdxV3LicenseManager +{ + private static final Logger LOG = LoggerFactory.getLogger( SpdxV3LicenseManager.class ); + + /** + * SPDX document containing the license information collected. All extracted licenses are added to the SPDX + * document + */ + SpdxDocument spdxDoc = null; + + /** + * Maps URLs to SPDX license ID's. The SPDX licenses could be an SPDX listed license or an extracted license. + */ + Map urlStringToSpdxLicenseId = new HashMap<>(); + + /** + * Map of extracted license ID's to the SPDX license + */ + Map extractedLicenses = new HashMap<>(); + + /** + * License manager will track any extracted SPDX licenses and map between SPDX licenses and Maven licenses. The + * mapping uses the license URL to uniquely identify the licenses. + * + * @param spdxDoc SPDX document to add any extracted licenses + * @param useStdLicenseSourceUrls if true, map any SPDX listed license source URL to license ID. Note: significant + * performance degradation + * @throws LicenseMapperException + */ + public SpdxV3LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUrls ) throws LicenseMapperException + { + this.spdxDoc = spdxDoc; + initializeUrlMap(); + } + + /** + * Initialize the URL map from the SPDX listed licenses + * + * @throws LicenseMapperException + */ + private void initializeUrlMap() throws LicenseMapperException + { + this.urlStringToSpdxLicenseId.putAll( MavenToSpdxLicenseMapper.getInstance().getMap() ); + } + + /** + * Add a non-listed license to the SPDX document. Once added, the non-listed license can be referenced by the + * license ID + * + * @param license + * @throws LicenseManagerException + */ + public void addExtractedLicense( NonStandardLicense license ) throws LicenseManagerException + { + CustomLicense spdxLicense; + try + { + spdxLicense = spdxDoc.createCustomLicense( spdxDoc.getIdPrefix() + "/" + license.getLicenseId() ) + .setLicenseText( license.getExtractedText() ) + .setName( license.getName() ) + .setComment( license.getComment() ) + .build(); + for (String crossRef:license.getCrossReference()) { + spdxLicense.getSeeAlsos().add( crossRef ); + } + spdxDoc.getElements().add( spdxLicense ); + } + catch ( InvalidSPDXAnalysisException e ) + { + String licenseId = license.getLicenseId(); + if ( licenseId == null ) + { + licenseId = "[NullLicenseId]"; + } + throw new LicenseManagerException( "Unable to add non listed license " + licenseId, e ); + } + // add to URL mapping + String[] urls = license.getCrossReference(); + if ( urls != null ) + { + for ( String url : urls ) + { + if ( this.urlStringToSpdxLicenseId.containsKey( url ) ) + { + String oldLicenseId = urlStringToSpdxLicenseId.get( url ); + LOG.warn( + "Duplicate URL for SPDX extracted license. Replacing " + oldLicenseId + " with " + + license.getLicenseId() + " for " + url ); + } + LOG.debug( "Adding URL mapping for non-standard license " + license.getLicenseId() ); + this.urlStringToSpdxLicenseId.put( url, license.getLicenseId() ); + } + } + // add to extracted license cache + extractedLicenses.put( license.getLicenseId(), spdxLicense ); + } + + /** + * Map a list of Maven licenses to an SPDX license. If no licenses are supplied, SpdxNoAssertion license is + * returned. if a single license is supplied, the mapped SPDX license is returned. If multiple licenses are + * supplied, a conjunctive license is returned containing all mapped SPDX licenses. + * + * @return + * @throws LicenseManagerException + */ + public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList ) throws LicenseManagerException + { + try { + if ( licenseList == null || licenseList.isEmpty() ) + { + return new NoAssertionLicense(); + } + else if ( licenseList.size() == 1 ) + { + return mavenLicenseToSpdxLicense( licenseList.get( 0 ) ); + } + else + { + Set spdxLicenses = new HashSet<>(); + for ( License license : licenseList ) + { + spdxLicenses.add( mavenLicenseToSpdxLicense( license ) ); + } + return spdxDoc.createConjunctiveLicenseSet( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .addAllMember( spdxLicenses ) + .build(); + } + } catch ( InvalidSPDXAnalysisException e ) + { + throw new LicenseManagerException( "Error converting Maven license to SPDX license", e ); + } + } + + /** + * Map a Maven license to an SPDX license based on the URL + * + * @param mavenLicense license to map to a listed SPDX license + * @return SPDX license + * @throws LicenseManagerException thrown if no SPDX listed or extracted license exists with the same URL + */ + public AnyLicenseInfo mavenLicenseToSpdxLicense( License mavenLicense ) throws LicenseManagerException + { + if ( mavenLicense.getUrl() == null ) + { + throw new LicenseManagerException( + "Can not map maven license " + mavenLicense.getName() + " No URL exists to provide a mapping" ); + } + String licenseId = this.urlStringToSpdxLicenseId.get( mavenLicense.getUrl().replaceAll("https:", "http:") ); + if ( licenseId == null ) + { + throw new LicenseManagerException( + "Can not map maven license " + mavenLicense.getName() + " No listed or extracted license matches the URL " + mavenLicense.getUrl() ); + } + AnyLicenseInfo retval = extractedLicenses.get( licenseId ); + if ( retval == null ) + { + try + { + retval = LicenseInfoFactory.parseSPDXLicenseString( licenseId, spdxDoc.getModelStore(), + spdxDoc.getIdPrefix(), + spdxDoc.getCopyManager(), null ); + } + catch ( InvalidLicenseStringException e ) + { + throw new LicenseManagerException( + "Can not map maven license " + mavenLicense.getName() + " Invalid listed or extracted license id matching the URL " + mavenLicense.getUrl() ); + } + catch ( DefaultStoreNotInitialized e ) + { + throw new LicenseManagerException( "Default model store not initialized" ); + } + } + return retval; + } + + /** + * Create a Maven license from the SPDX license + * + * @param spdxLicense + * @return + * @throws LicenseManagerException + */ + public License spdxLicenseToMavenLicense( AnyLicenseInfo spdxLicense ) throws LicenseManagerException + { + if ( spdxLicense instanceof CustomLicense ) + { + return spdxNonStdLicenseToMavenLicense( (CustomLicense) spdxLicense ); + } + else if ( spdxLicense instanceof ListedLicense ) + { + return spdxStdLicenseToMavenLicense( (ListedLicense) spdxLicense ); + } + else + { + throw new LicenseManagerException( + "Can not create a Maven license from this SPDX license type. " + "Must be an ExtractedLicenseInfo or an SpdxListedLicense " ); + } + } + + private License spdxStdLicenseToMavenLicense( ListedLicense spdxLicense ) throws LicenseManagerException + { + try + { + License retval = new License(); + // name + if ( spdxLicense.getName().isPresent() && !spdxLicense.getName().get().isEmpty() ) + { + retval.setName( spdxLicense.getName().get() ); + } + else + { + retval.setName( SpdxListedLicenseModelStore.objectUriToLicenseOrExceptionId( spdxLicense.getObjectUri() ) ); + } + // comment + if ( spdxLicense.getComment().isPresent() && !spdxLicense.getComment().get().isEmpty() ) + { + retval.setComments( spdxLicense.getComment().get() ); + } + // url + for (String url:spdxLicense.getSeeAlsos()) { + retval.setUrl( url ); + } + if ( spdxLicense.getSeeAlsos().size() > 1 ) + { + LOG.warn( + "SPDX license " + SpdxListedLicenseModelStore.objectUriToLicenseOrExceptionId( spdxLicense.getObjectUri() ) + + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + } + return retval; + } catch ( InvalidSPDXAnalysisException e ) + { + throw new LicenseManagerException( "Error converting SPDX Listed License to Maven license", e ); + } + } + + private License spdxNonStdLicenseToMavenLicense( CustomLicense spdxLicense ) throws LicenseManagerException + { + try + { + License retval = new License(); + // license ID + String licenseId = spdxLicense.getObjectUri().substring( spdxLicense.getIdPrefix().length() ); + // name + if ( spdxLicense.getName().isPresent() && !spdxLicense.getName().get().isEmpty() ) + { + retval.setName( spdxLicense.getName().get() ); + } + else + { + retval.setName( licenseId ); + } + // comment + if ( spdxLicense.getComment().isPresent() && !spdxLicense.getComment().get().isEmpty() ) + { + retval.setComments( spdxLicense.getComment().get() ); + } + // url + for (String url:spdxLicense.getSeeAlsos()) { + retval.setUrl( url ); + } + if ( spdxLicense.getSeeAlsos().size() > 1 ) + { + LOG.warn( + "SPDX license " + licenseId + + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + } + return retval; + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new LicenseManagerException( "Error converting SPDX non-standard license to Maven license", e ); + } + } +} diff --git a/src/test/java/org/spdx/maven/utils/TestLicenseManager.java b/src/test/java/org/spdx/maven/utils/TestLicenseManager.java index 055b15e..2e0af47 100644 --- a/src/test/java/org/spdx/maven/utils/TestLicenseManager.java +++ b/src/test/java/org/spdx/maven/utils/TestLicenseManager.java @@ -40,7 +40,7 @@ import org.apache.maven.model.License; /** - * Unit tests for LicenseManager class + * Unit tests for SpdxV2LicenseManager class * * @author Gary O'Neall */ @@ -92,7 +92,7 @@ public void tearDown() throws Exception } /** - * Test method for {@link org.spdx.maven.utils.LicenseManager#LicenseManager(org.spdx.rdfparser.SpdxDocument,boolean)}. + * Test method for {@link org.spdx.maven.utils.SpdxV2LicenseManager#LicenseManager(org.spdx.rdfparser.SpdxDocument,boolean)}. * * @throws LicenseMapperException */ @@ -100,11 +100,11 @@ public void tearDown() throws Exception public void testLicenseManager() throws LicenseMapperException { @SuppressWarnings( "unused" ) - LicenseManager licenseManager = new LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); } /** - * Test method for {@link org.spdx.maven.utils.LicenseManager#addExtractedLicense(org.spdx.maven.NonStandardLicense)}. + * Test method for {@link org.spdx.maven.utils.SpdxV2LicenseManager#addExtractedLicense(org.spdx.maven.NonStandardLicense)}. * * @throws MalformedURLException * @throws LicenseManagerException @@ -114,7 +114,7 @@ public void testLicenseManager() throws LicenseMapperException @Test public void testAddNonStandardLicense() throws MalformedURLException, LicenseManagerException, InvalidSPDXAnalysisException, LicenseMapperException { - LicenseManager licenseManager = new LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); NonStandardLicense lic = new NonStandardLicense(); final String COMMENT = "comment"; final String[] CROSS_REF_STR = new String[] {"http://www.licenseRef1", "http://www.licenseref2"}; @@ -159,7 +159,7 @@ public void testAddNonStandardLicense() throws MalformedURLException, LicenseMan } /** - * Test method for {@link org.spdx.maven.utils.LicenseManager#mavenLicenseListToSpdxLicense(java.util.List)}. + * Test method for {@link org.spdx.maven.utils.SpdxV2LicenseManager#mavenLicenseListToSpdxLicense(java.util.List)}. * * @throws LicenseManagerException * @throws LicenseMapperException @@ -182,7 +182,7 @@ public void testMavenLicenseListToSpdxLicense() throws LicenseManagerException, licenseList.add( apache ); licenseList.add( apsl ); - LicenseManager licenseManager = new LicenseManager( spdxDoc, true ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, true ); AnyLicenseInfo result = licenseManager.mavenLicenseListToSpdxLicense( licenseList ); assertTrue( result instanceof ConjunctiveLicenseSet ); @@ -206,7 +206,7 @@ public void testMavenLicenseListToSpdxLicense() throws LicenseManagerException, } /** - * Test method for {@link org.spdx.maven.utils.LicenseManager#mavenLicenseToSpdxLicense(org.apache.maven.model.License)}. + * Test method for {@link org.spdx.maven.utils.SpdxV2LicenseManager#mavenLicenseToSpdxLicense(org.apache.maven.model.License)}. * * @throws LicenseManagerException * @throws MalformedURLException @@ -222,7 +222,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf License apache = new License(); apache.setName( LICENSE1_NAME ); apache.setUrl( APACHE_CROSS_REF_URL2 ); - LicenseManager licenseManager = new LicenseManager( spdxDoc, true ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, true ); AnyLicenseInfo result = licenseManager.mavenLicenseToSpdxLicense( apache ); assertTrue( result instanceof SpdxListedLicense ); @@ -258,7 +258,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf } /** - * Test method for {@link org.spdx.maven.utils.LicenseManager#spdxLicenseToMavenLicense(org.spdx.rdfparser.AnyLicenseInfo)}. + * Test method for {@link org.spdx.maven.utils.SpdxV2LicenseManager#spdxLicenseToMavenLicense(org.spdx.rdfparser.AnyLicenseInfo)}. * * @throws LicenseManagerException * @throws LicenseMapperException @@ -267,7 +267,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf @Test public void testSpdxLicenseToMavenLicense() throws LicenseManagerException, LicenseMapperException, InvalidSPDXAnalysisException { - LicenseManager licenseManager = new LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); // standard license AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseString( APACHE_LICENSE_ID ); License result = licenseManager.spdxLicenseToMavenLicense( licenseInfo ); From 68130aa494c5d4067a6a5512ec1d6001081fd280 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Fri, 8 Nov 2024 16:42:41 -0800 Subject: [PATCH 02/10] Intermediate checkin - saving work Signed-off-by: Gary O'Neall --- pom.xml | 2 +- src/main/java/org/spdx/maven/Annotation.java | 31 - src/main/java/org/spdx/maven/Checksum.java | 63 ++ .../java/org/spdx/maven/CreateSpdxMojo.java | 35 +- .../org/spdx/maven/ExternalReference.java | 68 +- .../java/org/spdx/maven/OutputFormat.java | 18 +- src/main/java/org/spdx/maven/Packaging.java | 37 +- src/main/java/org/spdx/maven/SnippetInfo.java | 18 +- .../utils/AbstractDependencyBuilder.java | 190 ++++ .../utils/AbstractDependencyInformation.java | 42 - .../maven/utils/AbstractDocumentBuilder.java | 72 +- .../maven/utils/MavenToSpdxLicenseMapper.java | 95 +- .../spdx/maven/utils/SpdxDocumentBuilder.java | 2 +- .../maven/utils/SpdxExternalIdBuilder.java | 43 + .../maven/utils/SpdxExternalRefBuilder.java | 25 +- .../spdx/maven/utils/SpdxFileCollector.java | 16 +- .../maven/utils/SpdxProjectInformation.java | 68 +- .../maven/utils/SpdxSourceFileParser.java | 18 +- ...tion.java => SpdxV2DependencyBuilder.java} | 809 ++++++--------- .../utils/SpdxV2DependencyInformation.java | 42 - .../maven/utils/SpdxV2DocumentBuilder.java | 436 +++++++- .../spdx/maven/utils/SpdxV2FileCollector.java | 700 +++++++++++++ .../maven/utils/SpdxV3DependencyBuilder.java | 960 ++++++++++++++++++ .../utils/SpdxV3DependencyInformation.java | 42 - .../maven/utils/SpdxV3DocumentBuilder.java | 75 +- .../utils/TestMavenToSpdxLicenseMapper.java | 10 +- 26 files changed, 2962 insertions(+), 955 deletions(-) create mode 100644 src/main/java/org/spdx/maven/Checksum.java create mode 100644 src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java delete mode 100644 src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxExternalIdBuilder.java rename src/main/java/org/spdx/maven/utils/{SpdxDependencyInformation.java => SpdxV2DependencyBuilder.java} (62%) delete mode 100644 src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java delete mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java diff --git a/pom.xml b/pom.xml index 6868ef3..4afbf6f 100644 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,7 @@ org.spdx java-spdx-library - 2.0.0-Alpha + 2.0.1-SNAPSHOT org.spdx diff --git a/src/main/java/org/spdx/maven/Annotation.java b/src/main/java/org/spdx/maven/Annotation.java index 2f6052c..2fb1f0d 100644 --- a/src/main/java/org/spdx/maven/Annotation.java +++ b/src/main/java/org/spdx/maven/Annotation.java @@ -15,8 +15,6 @@ */ package org.spdx.maven; -import org.apache.maven.plugin.MojoExecutionException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,35 +120,6 @@ public void setAnnotationComment( String annotationComment ) this.annotationComment = annotationComment; } - - /** - * @param spdxDoc SPDX document which will contain the annotation - * @return an SPDX model version of the annotation - */ - public org.spdx.library.model.Annotation toSpdxAnnotation( SpdxDocument spdxDoc ) throws MojoExecutionException - { - AnnotationType annotationType = AnnotationType.OTHER; - try - { - annotationType = AnnotationType.valueOf( this.annotationType ); - } - catch ( Exception ex ) - { - throw new MojoExecutionException( "Invalid annotation type "+this.annotationType ); - } - try - { - return spdxDoc.createAnnotation( this.annotator, - annotationType, - annotationDate, - annotationComment ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new MojoExecutionException( "Error creating annotation.", e ); - } - } - public void logInfo() { LOG.debug( diff --git a/src/main/java/org/spdx/maven/Checksum.java b/src/main/java/org/spdx/maven/Checksum.java new file mode 100644 index 0000000..63e794a --- /dev/null +++ b/src/main/java/org/spdx/maven/Checksum.java @@ -0,0 +1,63 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven; + +/** + * Holds the value and algorithm of a checksum used in the SPDX document + * + * @author Gary O'Neall + * + */ +public class Checksum +{ + + private String value; + private String algorithm; + + /** + * @param algorithm checksum algorithm + * @param value checksum result + */ + public Checksum( String algorithm, String value ) + { + this.algorithm = algorithm; + this.value = value; + } + + /** + * @return the value + */ + public String getValue() + { + return value; + } + + /** + * @param value the value to set + */ + public void setValue( String value ) + { + this.value = value; + } + + /** + * @return the algorithm + */ + public String getAlgorithm() + { + return algorithm; + } + + /** + * @param algorithm the algorithm to set + */ + public void setAlgorithm( String algorithm ) + { + this.algorithm = algorithm; + } + + + +} diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index 3a4e3a2..185f489 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -37,19 +37,19 @@ import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException; import org.apache.maven.shared.dependency.graph.DependencyNode; import org.apache.maven.shared.model.fileset.FileSet; -import org.spdx.core.CoreModelObject; import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; import org.spdx.maven.utils.LicenseMapperException; import org.spdx.maven.utils.SpdxBuilderException; import org.spdx.maven.utils.SpdxCollectionException; import org.spdx.maven.utils.SpdxDefaultFileInformation; -import org.spdx.maven.utils.AbstractDependencyInformation; +import org.spdx.maven.utils.AbstractDependencyBuilder; import org.spdx.maven.utils.AbstractDocumentBuilder; import org.spdx.maven.utils.SpdxFileCollector; import org.spdx.maven.utils.SpdxProjectInformation; -import org.spdx.maven.utils.SpdxV2DependencyInformation; +import org.spdx.maven.utils.SpdxV2DependencyBuilder; import org.spdx.maven.utils.SpdxV2DocumentBuilder; -import org.spdx.maven.utils.SpdxV3DependencyInformation; +import org.spdx.maven.utils.SpdxV3DependencyBuilder; import org.spdx.maven.utils.SpdxV3DocumentBuilder; import java.io.File; @@ -504,13 +504,12 @@ public void execute() throws MojoExecutionException getLog().info( "Creating SPDX File " + spdxFile.getPath() ); AbstractDocumentBuilder builder = initSpdxDocumentBuilder( outputFormatEnum ); - CoreModelObject spdxDoc = builder.getSpdxDoc(); // fill project information try { SpdxProjectInformation projectInformation = getSpdxProjectInfoFromParameters( builder ); - projectInformation.logInfo( spdxDoc ); + projectInformation.logInfo(); builder.fillSpdxDocumentInformation( projectInformation ); } catch ( InvalidSPDXAnalysisException e2 ) @@ -538,9 +537,7 @@ public void execute() throws MojoExecutionException // add dependencies information try { - AbstractDependencyInformation dependencyInformation = getSpdxDependencyInformation( builder, outputFormatEnum ); - - builder.addDependencyInformation( dependencyInformation ); + buildSpdxDependencyInformation( builder, outputFormatEnum ); } catch ( LicenseMapperException e1 ) { @@ -562,7 +559,7 @@ public void execute() throws MojoExecutionException projectHelper.attachArtifact( mavenProject, artifactType, spdxFile ); // check errors - List spdxErrors = builder.getSpdxDoc().verify(); + List spdxErrors = builder.verify(); if ( spdxErrors != null && spdxErrors.size() > 0 ) { getLog().warn( "The following errors were found in the SPDX file:\n " + String.join( "\n ", spdxErrors ) ); @@ -616,7 +613,7 @@ private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputForm spdxDocumentNamespace = spdxDocumentNamespace.replace( " ", "%20" ); } URI namespaceUri = new URI( spdxDocumentNamespace ); - if ( OutputFormat.JSON_LD.equals( outputFormatEnum ) ) { + if ( SpdxMajorVersion.VERSION_3.equals( outputFormatEnum.getSpecVersion() ) ) { builder = new SpdxV3DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); } @@ -655,25 +652,25 @@ private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputForm } /** - * Collect dependency information from Maven dependencies + * Collect dependency information from Maven dependencies and adds it to the builder SPDX document * * @param builder SPDX document builder * @throws LicenseMapperException * @throws InvalidSPDXAnalysisException */ - private AbstractDependencyInformation getSpdxDependencyInformation( AbstractDocumentBuilder builder, OutputFormat outputFormatEnum ) + private void buildSpdxDependencyInformation( AbstractDocumentBuilder builder, OutputFormat outputFormatEnum ) throws LicenseMapperException, InvalidSPDXAnalysisException, DependencyGraphBuilderException { - AbstractDependencyInformation retval; + AbstractDependencyBuilder dependencyBuilder; if ( builder instanceof SpdxV3DocumentBuilder ) { - retval = new SpdxV3DependencyInformation( (SpdxV3DocumentBuilder)builder, createExternalRefs, + dependencyBuilder = new SpdxV3DependencyBuilder( (SpdxV3DocumentBuilder)builder, createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); } else { - retval = new SpdxV2DependencyInformation( (SpdxV2DocumentBuilder)builder, + dependencyBuilder = new SpdxV2DependencyBuilder( (SpdxV2DocumentBuilder)builder, createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); } @@ -684,10 +681,8 @@ private AbstractDependencyInformation getSpdxDependencyInformation( AbstractDocu request.setProject( mavenProject ); DependencyNode parentNode = dependencyGraphBuilder.buildDependencyGraph( request, null ); - retval.addMavenDependencies( mavenProjectBuilder, session, mavenProject, parentNode, builder.getProjectPackage() ); + dependencyBuilder.addMavenDependencies( mavenProjectBuilder, session, mavenProject, parentNode, builder.getProjectPackage() ); } - - return retval; } private void logFileSpecificInfo( HashMap fileSpecificInformation ) @@ -899,7 +894,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen packageFile = new File(mainArtifact.getFile().getParent() + File.separator + packageFileName); } - Set checksums = null; + Set checksums = null; if ( packageFile != null && packageFile.exists() ) { try diff --git a/src/main/java/org/spdx/maven/ExternalReference.java b/src/main/java/org/spdx/maven/ExternalReference.java index e32d412..0de1ed5 100644 --- a/src/main/java/org/spdx/maven/ExternalReference.java +++ b/src/main/java/org/spdx/maven/ExternalReference.java @@ -15,14 +15,6 @@ */ package org.spdx.maven; -import org.apache.maven.plugin.MojoExecutionException; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.ExternalRef; -import org.spdx.library.model.ReferenceType; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.enumerations.ReferenceCategory; -import org.spdx.library.referencetype.ListedReferenceTypes; - /** * An External Reference allows a Package to reference an external source of additional information, metadata, * enumerations, asset identifiers, or downloadable content believed to be relevant to the Package. @@ -42,37 +34,35 @@ public class ExternalReference private String comment; - public ExternalRef getExternalRef( SpdxDocument spdxDoc ) throws MojoExecutionException + /** + * @return the category + */ + public String getCategory() + { + return category; + } + + /** + * @return the type + */ + public String getType() + { + return type; + } + + /** + * @return the locator + */ + public String getLocator() + { + return locator; + } + + /** + * @return the comment + */ + public String getComment() { - ReferenceCategory cat = null; - - try { - cat = ReferenceCategory.valueOf( category.replaceAll( "-", "_" ) ); - } - catch ( Exception ex ) - { - throw new MojoExecutionException("External reference category " + category + " is not recognized as a valid, standard category." ); - } - ReferenceType refType = null; - try - { - refType = ListedReferenceTypes.getListedReferenceTypes().getListedReferenceTypeByName( type ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new MojoExecutionException( "Error getting listed reference type for " + type, e ); - } - if ( refType == null ) - { - throw new MojoExecutionException( "Listed reference type not found for " + type ); - } - try - { - return spdxDoc.createExternalRef( cat, refType, locator, comment ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new MojoExecutionException( "Error creating External Reference", e ); - } + return comment; } } diff --git a/src/main/java/org/spdx/maven/OutputFormat.java b/src/main/java/org/spdx/maven/OutputFormat.java index 050a622..4efc299 100644 --- a/src/main/java/org/spdx/maven/OutputFormat.java +++ b/src/main/java/org/spdx/maven/OutputFormat.java @@ -16,6 +16,7 @@ package org.spdx.maven; import java.io.File; +import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; /** * OutputFormat utility enum @@ -24,19 +25,23 @@ */ public enum OutputFormat { - RDF_XML("RDF/XML", "spdx.rdf.xml", ".rdf.xml"), - JSON("JSON", "spdx.json", ".json"), - JSON_LD("JSON-LD", "spdx.json-ld.json", ".json-ld.json"); + + RDF_XML("RDF/XML", "spdx.rdf.xml", ".rdf.xml", SpdxMajorVersion.VERSION_2), + JSON("JSON", "spdx.json", ".json", SpdxMajorVersion.VERSION_2), + JSON_LD("JSON-LD", "spdx.json-ld.json", ".json-ld.json", SpdxMajorVersion.VERSION_3); private final String value; private final String artifactType; private final String fileType; + private final SpdxMajorVersion specVersion; - private OutputFormat(final String value, final String artifactType, final String fileType) + private OutputFormat(final String value, final String artifactType, final String fileType, + final SpdxMajorVersion specVersion) { this.value = value; this.artifactType = artifactType; this.fileType = fileType; + this.specVersion = specVersion; } public static OutputFormat getOutputFormat(final String format, final File file) @@ -80,4 +85,9 @@ public String getFileType() { return fileType; } + + public SpdxMajorVersion getSpecVersion() + { + return specVersion; + } } diff --git a/src/main/java/org/spdx/maven/Packaging.java b/src/main/java/org/spdx/maven/Packaging.java index 933ac12..cadefe2 100644 --- a/src/main/java/org/spdx/maven/Packaging.java +++ b/src/main/java/org/spdx/maven/Packaging.java @@ -15,7 +15,8 @@ */ package org.spdx.maven; -import org.spdx.library.model.enumerations.Purpose; +import org.spdx.library.model.v2.enumerations.Purpose; +import org.spdx.library.model.v3_0_1.software.SoftwarePurpose; /** * Packaging utility enum @@ -24,21 +25,23 @@ */ public enum Packaging { - POM("pom", Purpose.INSTALL), - EJB("ejb", Purpose.LIBRARY), - JAR("jar", Purpose.LIBRARY), - MAVEN_PLUGIN("maven-plugin", Purpose.LIBRARY), - WAR("war", Purpose.APPLICATION), - EAR("ear", Purpose.APPLICATION), - RAR("rar", Purpose.OTHER); + POM("pom", Purpose.INSTALL, SoftwarePurpose.INSTALL), + EJB("ejb", Purpose.LIBRARY, SoftwarePurpose.LIBRARY), + JAR("jar", Purpose.LIBRARY, SoftwarePurpose.LIBRARY), + MAVEN_PLUGIN("maven-plugin", Purpose.LIBRARY, SoftwarePurpose.LIBRARY), + WAR("war", Purpose.APPLICATION, SoftwarePurpose.APPLICATION), + EAR("ear", Purpose.APPLICATION, SoftwarePurpose.APPLICATION), + RAR("rar", Purpose.OTHER, SoftwarePurpose.ARCHIVE); private final String name; - private final Purpose purpose; + private final Purpose v2Purpose; + private final SoftwarePurpose softwarePurpose; - private Packaging(final String name, final Purpose purpose) + private Packaging(final String name, final Purpose v2purpose, final SoftwarePurpose v3softwarePurpose) { this.name = name; - this.purpose = purpose; + this.v2Purpose = v2purpose; + this.softwarePurpose = v3softwarePurpose; } public static Packaging valueOfPackaging(String packagingValue) @@ -61,8 +64,16 @@ public String getName() return name; } - public Purpose getPurpose() + public Purpose getV2Purpose() { - return purpose; + return v2Purpose; + } + + /** + * @return the softwarePurpose + */ + public SoftwarePurpose getSoftwarePurpose() + { + return softwarePurpose; } } diff --git a/src/main/java/org/spdx/maven/SnippetInfo.java b/src/main/java/org/spdx/maven/SnippetInfo.java index 7d9be16..9fc9619 100644 --- a/src/main/java/org/spdx/maven/SnippetInfo.java +++ b/src/main/java/org/spdx/maven/SnippetInfo.java @@ -21,11 +21,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.InvalidLicenseStringException; -import org.spdx.library.model.license.LicenseInfoFactory; - +import org.spdx.core.DefaultStoreNotInitialized; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.InvalidLicenseStringException; import org.spdx.maven.utils.SpdxBuilderException; import org.slf4j.Logger; @@ -98,16 +98,16 @@ public String getComment() return this.comment; } - public AnyLicenseInfo getLicenseConcluded( SpdxDocument spdxDoc ) throws InvalidLicenseStringException + public AnyLicenseInfo getLicenseConcluded( SpdxDocument spdxDoc ) throws InvalidLicenseStringException, DefaultStoreNotInitialized { - return LicenseInfoFactory.parseSPDXLicenseString( this.concludedLicense, spdxDoc.getModelStore(), + return LicenseInfoFactory.parseSPDXLicenseStringCompatV2( this.concludedLicense, spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); } - public Collection getLicenseInfoInSnippet( SpdxDocument spdxDoc ) throws InvalidLicenseStringException + public Collection getLicenseInfoInSnippet( SpdxDocument spdxDoc ) throws InvalidLicenseStringException, DefaultStoreNotInitialized { List retval = new ArrayList<>(); - retval.add( LicenseInfoFactory.parseSPDXLicenseString( this.licenseInfoInSnippet, spdxDoc.getModelStore(), + retval.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( this.licenseInfoInSnippet, spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() )); return retval; } diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java new file mode 100644 index 0000000..a667ea8 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java @@ -0,0 +1,190 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.List; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.shared.dependency.graph.DependencyNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.maven.OutputFormat; + +/** + * Contains information about package dependencies collected from the Maven dependencies. + * + * Subclasses implement dependency information specific to SPDX spec major versions + * + * @author Gary O'Neall + * + */ +public abstract class AbstractDependencyBuilder +{ + + protected static final Logger LOG = LoggerFactory.getLogger( AbstractDependencyBuilder.class ); + protected boolean createExternalRefs; + protected boolean generatePurls; + protected boolean useArtifactID; + protected boolean includeTransitiveDependencies; + DateFormat format = new SimpleDateFormat( SpdxConstantsCompatV2.SPDX_DATE_FORMAT ); + + /** + * @param createExternalRefs if true, create external references for dependencies + * @param generatePurls if true, generate a Package URL and include as an external identifier for the dependencies + * @param useArtifactID if true, use the artifact ID for the name of the dependency package, otherwise use the Maven configured project name + * @param includeTransitiveDependencies If true, include transitive dependencies, otherwise include only direct dependencies + */ + public AbstractDependencyBuilder( boolean createExternalRefs, boolean generatePurls, + boolean useArtifactID, boolean includeTransitiveDependencies ) + { + this.createExternalRefs = createExternalRefs; + this.generatePurls = generatePurls; + this.useArtifactID = useArtifactID; + this.includeTransitiveDependencies = includeTransitiveDependencies; + } + + /** + * Adds information about Maven dependencies to the list of SPDX Dependencies + * + * @param mavenProjectBuilder project builder for the repo containing the POM file + * @param session Maven session for building the project + * @param mavenProject Mave project + * @param node Dependency node which contains all the dependencies + * @param pkg SPDX Package to attach the dependencies to + * @throws InvalidSPDXAnalysisException on errors generating SPDX + * @throws LicenseMapperException on errors mapping licenses or creating custom licenses + */ + public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, + MavenProject mavenProject, DependencyNode node, + CoreModelObject pkg ) throws LicenseMapperException, InvalidSPDXAnalysisException + { + List children = node.getChildren(); + + logDependencies( children ); + + for ( DependencyNode childNode : children ) + { + addMavenDependency( pkg, childNode, mavenProjectBuilder, session, mavenProject ); + } + } + + abstract void addMavenDependency( CoreModelObject parentPackage, DependencyNode dependencyNode, + ProjectBuilder mavenProjectBuilder, + MavenSession session, MavenProject mavenProject ) + throws LicenseMapperException, InvalidSPDXAnalysisException; + + + /** + * Converts an artifact file to an SPDX file + * + * @param file input file + * @param versionFilter Optional (nullable) version - if present, only return file formats that support the filter version + * @return SPDX file using the SPDX naming conventions if it exists, otherwise return null + */ + protected File artifactFileToSpdxFile( File file, SpdxMajorVersion versionFilter ) + { + for ( OutputFormat of: OutputFormat.values() ) + { + if ( versionFilter == null || versionFilter.equals( of.getSpecVersion() )) + { + File retval = getFileWithDifferentType( file, of.getFileType() ); + if ( retval != null && retval.exists() ) { + return retval; + } + } + } + return null; + } + + /** + * Convert a file to a different type (e.g. file.txt -> file.rdf with a type rdf parameter) + * + * @param file Input file + * @param type Type to change to + * @return New file type with only the type changed + */ + private File getFileWithDifferentType( File file, String type ) + { + String filePath = file.getAbsolutePath(); + int indexOfDot = filePath.lastIndexOf( '.' ); + if ( indexOfDot > 0 ) + { + filePath = filePath.substring( 0, indexOfDot + 1 ); + } + filePath = filePath + type; + File retval = new File( filePath ); + return retval; + } + + private void logDependencies( List dependencies ) + { + if ( !LOG.isDebugEnabled() ) + { + return; + } + LOG.debug( "Dependencies:" ); + if ( dependencies == null ) + { + LOG.debug( "\tNull dependencies" ); + return; + } + if ( dependencies.isEmpty() ) + { + LOG.debug( "\tZero dependencies" ); + return; + } + for ( DependencyNode node : dependencies ) + { + Artifact dependency = node.getArtifact(); + String filePath = dependency.getFile() != null ? dependency.getFile().getAbsolutePath() : "[NONE]"; + String scope = dependency.getScope() != null ? dependency.getScope() : "[NONE]"; + LOG.debug( + "ArtifactId: " + dependency.getArtifactId() + ", file path: " + filePath + ", Scope: " + scope ); + } + } + + /** + * Make an external document reference ID valid by replacing any invalid characters with dashes + * + * @param externalRefId + * @return valid external ref ID + */ + protected String fixExternalRefId( String externalRefId ) + { + StringBuilder sb = new StringBuilder(); + for ( int i = 0; i < externalRefId.length(); i++ ) + { + if ( validExternalRefIdChar( externalRefId.charAt( i ) ) ) + { + sb.append( externalRefId.charAt( i ) ); + } + else + { + sb.append( "-" ); + } + } + return sb.toString(); + } + + /** + * @param ch character to test + * @return true if the character is valid for use in an External Reference ID + */ + private boolean validExternalRefIdChar( char ch ) + { + return ( ( ch >= 'a' && ch <= 'z' ) || ( ch >= 'A' && ch <= 'Z' ) || ( ch >= '0' && ch <= '9' ) || ch == '.' || ch == '-' ); + } + +} diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java deleted file mode 100644 index 5fa6dae..0000000 --- a/src/main/java/org/spdx/maven/utils/AbstractDependencyInformation.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2024 Source Auditor Inc. - */ -package org.spdx.maven.utils; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.shared.dependency.graph.DependencyNode; - -/** - * Contains information about package dependencies collected from the Maven dependencies. - * - * Subclasses implement dependency information specific to SPDX spec major versions - * - * @author Gary O'Neall - * - */ -public abstract class AbstractDependencyInformation -{ - - /** - * - */ - public AbstractDependencyInformation() - { - // TODO Auto-generated constructor stub - } - - /** - * @param mavenProjectBuilder - * @param session - * @param mavenProject - * @param parentNode - * @param projectPackage - */ - public abstract void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, - MavenProject mavenProject, DependencyNode parentNode, - Object projectPackage ); - -} diff --git a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java index 9d00b74..9d7535d 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java @@ -6,6 +6,8 @@ import java.io.File; import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.List; import java.util.Set; @@ -15,9 +17,10 @@ import org.apache.maven.shared.model.fileset.FileSet; import org.spdx.core.CoreModelObject; import org.spdx.library.ModelCopyManager; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; import org.spdx.maven.NonStandardLicense; import org.spdx.maven.OutputFormat; -import org.spdx.storage.IModelStore; +import org.spdx.storage.ISerializableModelStore; /** * Abstract class to create SPDX documents. @@ -28,22 +31,18 @@ */ public abstract class AbstractDocumentBuilder { + protected static final String UNSPECIFIED = "UNSPECIFIED"; + public static final String NULL_SHA1 = "cf23df2207d99a74fbe169e3eba035e633b65d94"; protected MavenProject project; protected boolean generatePurls; protected File spdxFile; protected OutputFormat outputFormatEnum; protected boolean matchLicensesOnCrossReferenceUrls; - protected IModelStore modelStore; + protected ISerializableModelStore modelStore; protected ModelCopyManager copyManager; - - /** - * - */ - public AbstractDocumentBuilder() - { - // TODO Auto-generated constructor stub - } + protected DateFormat format = new SimpleDateFormat( SpdxConstantsCompatV2.SPDX_DATE_FORMAT ); + /** * @param project Maven Project @@ -93,36 +92,32 @@ public AbstractDocumentBuilder( MavenProject project, boolean generatePurls, Fil } /** - * @return + * @param projectInformation Information about project extracted from Maven metadata and parameters + * @throws SpdxBuilderException on errors adding document level information */ - public abstract CoreModelObject getSpdxDoc(); + public abstract void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) throws SpdxBuilderException; /** - * @param projectInformation + * Collect information at the file level, fill in the SPDX document + * + * @param sources Source directories to be included in the document + * @param baseDir project base directory used to construct the relative paths for the SPDX + * files + * @param pathSpecificInformation Map of path to file information used to override the default file information + * @param algorithms algorithms to use to generate checksums + * @throws SpdxBuilderException on errors collecting files */ - public abstract void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ); - - /** - * @param sources - * @param absolutePath - * @param defaultFileInformation - * @param pathSpecificInformation - * @param checksumAlgorithms - */ - public abstract void collectSpdxFileInformation( List sources, String absolutePath, + public abstract void collectSpdxFileInformation( List sources, String baseDir, SpdxDefaultFileInformation defaultFileInformation, HashMap pathSpecificInformation, - Set checksumAlgorithms ); - - /** - * @param dependencyInformation - */ - public abstract void addDependencyInformation( AbstractDependencyInformation dependencyInformation ); + Set checksumAlgorithms ) throws SpdxBuilderException; /** + * Saves the SPDX document to the file + * @throws SpdxBuilderException On any error saving the file * */ - public abstract void saveSpdxDocumentToFile(); + public abstract void saveSpdxDocumentToFile() throws SpdxBuilderException; /** * @param nonStandardLicenses @@ -130,21 +125,20 @@ public abstract void collectSpdxFileInformation( List sources, String a public abstract void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException; /** - * @return + * @return package representing the Mave project */ - public abstract Object getProjectPackage(); + public abstract CoreModelObject getProjectPackage(); /** - * @param algorithm - * @param checksum - * @return + * @param mavenLicenses list of licenses + * @return license expression representing the list of mavenLicenses */ - public abstract Object createChecksum( String algorithm, String checksum ); + public abstract String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ); /** - * @param mavenLicenses - * @return + * Verifies the top level document + * @return list of any errors or warnings */ - public abstract String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ); + public abstract List verify(); } diff --git a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java index f3001e8..507c61a 100644 --- a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java +++ b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java @@ -24,17 +24,21 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import org.apache.maven.model.License; - -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.SpdxListedLicense; -import org.spdx.library.model.license.SpdxNoAssertionLicense; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.SpdxListedLicense; +import org.spdx.library.model.v2.license.SpdxNoAssertionLicense; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.expandedlicensing.ListedLicense; +import org.spdx.library.model.v3_0_1.expandedlicensing.NoAssertionLicense; +import org.spdx.storage.IModelStore.IdType; import org.spdx.storage.listedlicense.LicenseJsonTOC; import org.slf4j.Logger; @@ -197,7 +201,7 @@ private void addManualMappings() } /** - * Map a list of Maven licenses to an SPDX license. If no licenses are supplied, SpdxNoAssertion license is + * Map a list of Maven licenses to an SPDX Spec version 2 license. If no licenses are supplied, SpdxNoAssertion license is * returned. if a single license is supplied, and a URL can be found matching a listed license, the listed license * is returned. if a single license is supplied, and a URL can not be found matching a listed license, * SpdxNoAssertion is returned. If multiple licenses are supplied, a conjunctive license is returned containing all @@ -208,7 +212,7 @@ private void addManualMappings() * @return * @throws InvalidSPDXAnalysisException */ - public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList, SpdxDocument spdxDoc ) throws InvalidSPDXAnalysisException + public AnyLicenseInfo mavenLicenseListToSpdxV2License( List licenseList, SpdxDocument spdxDoc ) throws InvalidSPDXAnalysisException { if ( licenseList == null ) { @@ -217,7 +221,7 @@ public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList, List spdxLicenses = new ArrayList<>(); for ( License license : licenseList ) { - SpdxListedLicense listedLicense = mavenLicenseToSpdxListedLicense( license ); + SpdxListedLicense listedLicense = mavenLicenseToSpdxV2ListedLicense( license ); if ( listedLicense != null ) { spdxLicenses.add( listedLicense ); @@ -238,7 +242,76 @@ else if ( spdxLicenses.size() == 1 ) } } - private SpdxListedLicense mavenLicenseToSpdxListedLicense( License license ) + private SpdxListedLicense mavenLicenseToSpdxV2ListedLicense( License license ) + { + if ( license == null ) + { + return null; + } + if ( license.getUrl() == null || license.getUrl().isEmpty() ) + { + return null; + } + String spdxId = this.urlStringToSpdxLicenseId.get( license.getUrl().replaceAll( "https", "http" ) ); + if ( spdxId == null ) + { + return null; + } + try + { + return LicenseInfoFactory.getListedLicenseByIdCompatV2( spdxId ); + } + catch ( InvalidSPDXAnalysisException e ) + { + return null; + } + } + + /** + * Map a list of Maven licenses to an SPDX Spec version 2 license. If no licenses are supplied, SpdxNoAssertion license is + * returned. if a single license is supplied, and a URL can be found matching a listed license, the listed license + * is returned. if a single license is supplied, and a URL can not be found matching a listed license, + * SpdxNoAssertion is returned. If multiple licenses are supplied, a conjunctive license is returned containing all + * mapped SPDX licenses. + * + * @param licenseList list of licenses + * @param spdxDoc SPDX document which will hold the licenses + * @return + * @throws InvalidSPDXAnalysisException + */ + public org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo mavenLicenseListToSpdxV3License( List licenseList, + Element spdxDoc ) throws InvalidSPDXAnalysisException + { + if ( licenseList == null ) + { + return new NoAssertionLicense(); + } + List spdxLicenses = new ArrayList<>(); + for ( License license : licenseList ) + { + ListedLicense listedLicense = mavenLicenseToSpdxV3ListedLicense( license ); + if ( listedLicense != null ) + { + spdxLicenses.add( listedLicense ); + } + } + if ( spdxLicenses.size() < 1 ) + { + return new NoAssertionLicense(); + } + else if ( spdxLicenses.size() == 1 ) + { + return spdxLicenses.get( 0 ); + } + else + { + return spdxDoc.createConjunctiveLicenseSet( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .addAllMember( new HashSet<>( spdxLicenses ) ) + .build(); + } + } + + private ListedLicense mavenLicenseToSpdxV3ListedLicense( License license ) { if ( license == null ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java index 535c6a4..2bfeffa 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java @@ -437,7 +437,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation { try { - pkg.getExternalRefs().add( externalRef.getExternalRef( spdxDoc ) ); + pkg.getExternalRefs().add( externalRef.convertExternalRef( spdxDoc ) ); } catch ( MojoExecutionException | InvalidSPDXAnalysisException e ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxExternalIdBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxExternalIdBuilder.java new file mode 100644 index 0000000..de5d68c --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxExternalIdBuilder.java @@ -0,0 +1,43 @@ +package org.spdx.maven.utils; + +import java.util.Collection; +import java.util.List; +import org.apache.maven.project.MavenProject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.model.v3_0_1.core.ExternalIdentifier; +import org.spdx.library.model.v3_0_1.core.ExternalIdentifierType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.storage.IModelStore.IdType; + +public class SpdxExternalIdBuilder +{ + + private static final Logger LOG = LoggerFactory.getLogger( SpdxExternalIdBuilder.class ); + + public static Collection getDefaultExternalIdentifiers( SpdxDocument spdxDoc, + boolean generatePurls, MavenProject project ) + { + ExternalIdentifier generatedPurlExternalIdentifier = + generatePurls ? generatePurlExternalIdentifier( spdxDoc, project ) : null; + return generatedPurlExternalIdentifier == null ? List.of() : List.of( generatedPurlExternalIdentifier ); + } + + private static ExternalIdentifier generatePurlExternalIdentifier( SpdxDocument spdxDoc, MavenProject project ) + { + try + { + return spdxDoc.createExternalIdentifier( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .setExternalIdentifierType( ExternalIdentifierType.PACKAGE_URL ) + .setIdentifier( SpdxExternalRefBuilder.generatePurl( project ) ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + LOG.warn( "Invalid reference type \"purl\" for generated purl external ref"); + return null; + } + } + +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java index d93dd57..d27b4e1 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java @@ -4,31 +4,34 @@ import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.List; -import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.ExternalRef; -import org.spdx.library.model.ReferenceType; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.enumerations.ReferenceCategory; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.model.v2.ExternalRef; +import org.spdx.library.model.v2.ReferenceType; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.enumerations.ReferenceCategory; public class SpdxExternalRefBuilder { private static final Logger LOG = LoggerFactory.getLogger( SpdxExternalRefBuilder.class ); - public static Collection getDefaultExternalRefs( SpdxDocument spdxDoc, boolean generatePurls, MavenProject project ) { - ExternalRef generatedPurlExternalRef = generatePurls ? generatePurlExternalRef( spdxDoc, project ) : null; + public static Collection getDefaultExternalRefs( SpdxDocument spdxDoc, + boolean generatePurls, MavenProject project ) { + ExternalRef generatedPurlExternalRef = + generatePurls ? generatePurlV2ExternalRef( spdxDoc, project ) : null; return generatedPurlExternalRef == null ? List.of() : List.of( generatedPurlExternalRef ); } - private static ExternalRef generatePurlExternalRef( SpdxDocument spdxDoc, MavenProject project ) + private static ExternalRef generatePurlV2ExternalRef( SpdxDocument spdxDoc, + MavenProject project ) { try { - return spdxDoc.createExternalRef( ReferenceCategory.PACKAGE_MANAGER, new ReferenceType("http://spdx.org/rdf/references/purl"), + return spdxDoc.createExternalRef( ReferenceCategory.PACKAGE_MANAGER, + new ReferenceType("http://spdx.org/rdf/references/purl"), generatePurl( project ), null ); } catch ( InvalidSPDXAnalysisException e ) @@ -38,7 +41,7 @@ private static ExternalRef generatePurlExternalRef( SpdxDocument spdxDoc, MavenP } } - private static String generatePurl( MavenProject project ) + public static String generatePurl( MavenProject project ) { return "pkg:maven/" + project.getGroupId() + "/" + URLEncoder.encode( project.getArtifactId(), StandardCharsets.UTF_8 ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java index 45f7876..c018abb 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java @@ -29,6 +29,7 @@ import org.apache.maven.shared.model.fileset.util.FileSetManager; import org.spdx.core.CoreModelObject; import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.maven.Checksum; import org.spdx.maven.SnippetInfo; import org.spdx.storage.IModelStore.IdType; @@ -614,17 +615,16 @@ public static String convertChecksumToString( byte[] digestBytes ) * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. * * @param file file to generate checksum for - * @param spdxDoc SPDX document which will contain the checksum + * @param builder Builder for the SPDX document that will contain the checksum * @return SHA1 checksum of the input file * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read * @throws InvalidSPDXAnalysisException */ - public static String generateSha1( File file, SpdxDocument spdxDoc ) throws SpdxCollectionException, InvalidSPDXAnalysisException + public static CoreModelObject generateSha1( File file, AbstractDocumentBuilder builder ) throws SpdxCollectionException, InvalidSPDXAnalysisException { - Set sha1 = new HashSet<>(); - sha1.add( ChecksumAlgorithm.SHA1 ); - Checksum sha1Checksum = generateChecksum( file, sha1, spdxDoc ).iterator().next(); - return sha1Checksum.getValue(); + Set sha1 = new HashSet<>(); + sha1.add( "SHA-1" ); + return generateChecksum( file, sha1, builder ).iterator().next(); } /** @@ -637,7 +637,7 @@ public static String generateSha1( File file, SpdxDocument spdxDoc ) throws Spdx * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read * @throws InvalidSPDXAnalysisException */ - public static Set generateChecksum( File file, Set algorithms, + public static Set generateChecksum( File file, Set algorithms, AbstractDocumentBuilder builder ) throws SpdxCollectionException, InvalidSPDXAnalysisException { Set checksums = new HashSet<>(); @@ -668,7 +668,7 @@ public static Set generateChecksum( File file, Set algo digest.update( buffer ); String checksum = convertChecksumToString( digest.digest() ); - checksums.add( builder.createChecksum( algorithm, checksum ) ); + checksums.add( new Checksum( algorithm, checksum ) ); } return checksums; diff --git a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java index 5b05a6d..d7adee8 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java @@ -15,16 +15,13 @@ */ package org.spdx.maven.utils; -import java.net.URI; -import java.net.URISyntaxException; import java.util.Set; -import org.apache.jena.query.ModelStore; -import org.apache.maven.plugin.MojoExecutionException; import org.spdx.core.CoreModelObject; -import org.spdx.library.referencetype.ListedReferenceTypes; +import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.maven.Annotation; +import org.spdx.maven.Checksum; import org.spdx.maven.ExternalReference; import org.spdx.maven.Packaging; import org.spdx.storage.IModelStore; @@ -61,7 +58,7 @@ public class SpdxProjectInformation private Annotation[] packageAnnotations; private Annotation[] documentAnnotations; private ExternalReference[] externalRefs; - private Set checksums; + private Set checksums; private Packaging packaging; @@ -107,7 +104,7 @@ public void setDocumentComment( String documentComment ) /** * @return checksums for the project */ - public Set getChecksums() + public Set getChecksums() { return checksums; } @@ -115,7 +112,7 @@ public Set getChecksums() /** * @param checksums the checksums to set for the project */ - public void setChecksums( Set checksums ) + public void setChecksums( Set checksums ) { this.checksums = checksums; } @@ -340,8 +337,9 @@ public void setName( String name ) /** * Log information on all fields - typically used for debugging + * @throws InvalidSPDXAnalysisException */ - public void logInfo( CoreModelObject modelObject ) + public static void logInfo( CoreModelObject modelObject ) throws InvalidSPDXAnalysisException { if ( !LOG.isDebugEnabled() ) { return; @@ -363,7 +361,7 @@ public void logInfo( CoreModelObject modelObject ) /** * Log information on all fields - typically used for debugging */ - public void logInfo( SpdxDocument spdxDoc ) + public void logInfo() { if ( !LOG.isDebugEnabled() ) { return; @@ -410,59 +408,15 @@ public void logInfo( SpdxDocument spdxDoc ) { for ( ExternalReference externalReference : externalRefs ) { - ExternalRef externalRef; - try - { - externalRef = externalReference.getExternalRef( spdxDoc ); - StringBuilder externalRefString = new StringBuilder(); - try - { - externalRefString.append( externalRef.getReferenceCategory().toString() ); - } - catch ( InvalidSPDXAnalysisException e1 ) - { - externalRefString.append( "Invalid Reference Category" ); - } - externalRefString.append( ' ' ); - try - { - externalRefString.append( ListedReferenceTypes.getListedReferenceTypes().getListedReferenceName( - new URI( externalRef.getReferenceType().getIndividualURI() ) ) ); - } - catch ( InvalidSPDXAnalysisException | URISyntaxException e ) - { - externalRefString.append( "Invalid Reference Type" ); - } - externalRefString.append( ' ' ); - try - { - externalRefString.append( externalRef.getReferenceLocator() ); - } - catch ( InvalidSPDXAnalysisException e ) - { - externalRefString.append( "Invalid Reference Locator" ); - } - LOG.debug( "External Ref: " + externalRefString.toString() ); - } - catch ( MojoExecutionException e1 ) - { - LOG.error( "Invalid external reference", e1 ); - } - + LOG.debug( String.format( "External Ref: %s %s %s", externalReference.getCategory(), + externalReference.getType(), externalReference.getLocator()) ); } } if ( checksums != null && checksums.size() > 0 ) { for ( Checksum checksum : checksums ) { - try - { - String algorithm = SpdxFileCollector.checksumAlgorithms.get( checksum.getAlgorithm() ); - LOG.debug( "SPDX " + algorithm + ": " + checksum.getValue() ); - } catch ( InvalidSPDXAnalysisException e ) - { - LOG.debug( "Invalid SPDX checksum" ); - } + LOG.debug( "SPDX " + checksum.getAlgorithm() + ": " + checksum.getValue() ); } } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java b/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java index 00290c7..8462c46 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java +++ b/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java @@ -23,9 +23,6 @@ import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.InvalidLicenseStringException; -import org.spdx.library.model.license.LicenseInfoFactory; /** * Helper class with static methods to parse SPDX source files @@ -44,7 +41,7 @@ public class SpdxSourceFileParser * @param file Text file to parse * @return list of all license expressions found following SPDX-License-Identifier: */ - public static List parseFileForSpdxLicenses( File file ) throws SpdxSourceParserException + public static List parseFileForSpdxLicenses( File file ) throws SpdxSourceParserException { try { @@ -60,9 +57,9 @@ public static List parseFileForSpdxLicenses( File file ) throws } } - public static List parseTextForSpdxLicenses( String text ) throws SpdxSourceParserException + public static List parseTextForSpdxLicenses( String text ) throws SpdxSourceParserException { - List retval = new ArrayList<>(); + List retval = new ArrayList<>(); Matcher match = SPDX_LICENSE_PATTERN.matcher( text ); int pos = 0; while ( pos < text.length() && match.find( pos ) ) @@ -105,14 +102,7 @@ else if ( ch == ')' ) { pos = match.end() + 1; } - try - { - retval.add( LicenseInfoFactory.parseSPDXLicenseString( matchingLine ) ); - } - catch ( InvalidLicenseStringException e ) - { - throw new SpdxSourceParserException( "Invalid SPDX license string '" + matchingLine + "'." ); - } + retval.add( matchingLine ); } return retval; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java similarity index 62% rename from src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java rename to src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java index 3a027f2..b899aed 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java @@ -1,17 +1,6 @@ -/* - * Copyright 2014 Source Auditor Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. */ package org.spdx.maven.utils; @@ -21,24 +10,21 @@ import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; + import javax.annotation.Nullable; + import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Contributor; import org.apache.maven.model.License; -import org.apache.maven.model.Model; -import org.apache.maven.model.Resource; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; @@ -46,175 +32,203 @@ import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.shared.dependency.graph.DependencyNode; -import org.apache.maven.shared.model.fileset.FileSet; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; +import org.spdx.core.SpdxInvalidIdException; import org.spdx.jacksonstore.MultiFormatStore; import org.spdx.jacksonstore.MultiFormatStore.Format; import org.spdx.jacksonstore.MultiFormatStore.Verbose; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.SpdxConstants; -import org.spdx.library.SpdxInvalidIdException; -import org.spdx.library.model.Checksum; -import org.spdx.library.model.ExternalDocumentRef; -import org.spdx.library.model.ExternalSpdxElement; -import org.spdx.library.model.Relationship; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxElement; -import org.spdx.library.model.SpdxPackage; -import org.spdx.library.model.enumerations.AnnotationType; -import org.spdx.library.model.enumerations.ChecksumAlgorithm; -import org.spdx.library.model.enumerations.Purpose; -import org.spdx.library.model.enumerations.RelationshipType; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.SpdxNoAssertionLicense; - -import org.spdx.maven.CreateSpdxMojo; +import org.spdx.library.model.v2.Checksum; +import org.spdx.library.model.v2.ExternalDocumentRef; +import org.spdx.library.model.v2.ExternalSpdxElement; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxElement; +import org.spdx.library.model.v2.SpdxPackage; +import org.spdx.library.model.v2.enumerations.AnnotationType; +import org.spdx.library.model.v2.enumerations.Purpose; +import org.spdx.library.model.v2.enumerations.RelationshipType; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.SpdxNoAssertionLicense; +import org.spdx.maven.OutputFormat; import org.spdx.spdxRdfStore.RdfStore; -import org.spdx.storage.IModelStore.IdType; import org.spdx.storage.ISerializableModelStore; +import org.spdx.storage.IModelStore.IdType; import org.spdx.storage.simple.InMemSpdxStore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * Contains information about package dependencies collected from the Maven dependencies. - * + * Builds dependencies for a parent package based on Maven dependency information * @author Gary O'Neall + * */ -public class SpdxDependencyInformation +public class SpdxV2DependencyBuilder + extends AbstractDependencyBuilder { - private static final Logger LOG = LoggerFactory.getLogger( SpdxDependencyInformation.class ); - - /** - * List of all Relationships added for dependances To a related element - */ - private Map> relationships = new HashMap<>(); /** - * Map of namespaces to ExternalDocumentRefs - */ - private Map externalDocuments = new HashMap<>(); - private List documentAnnotations = new ArrayList<>(); - private SpdxV2LicenseManager licenseManager; - private SpdxDocument spdxDoc; - private boolean createExternalRefs = false; - private boolean generatePurls = false; - private boolean useArtifactID = false; - private boolean includeTransitiveDependencies = false; - DateFormat format = new SimpleDateFormat( SpdxConstants.SPDX_DATE_FORMAT ); - - /** - */ - public SpdxDependencyInformation( SpdxV2LicenseManager licenseManager, - SpdxDocument spdxDoc, boolean createExternalRefs, boolean generatePurls, boolean useArtifactID, - boolean includeTransitiveDependencies ) - { - this.licenseManager = licenseManager; - this.spdxDoc = spdxDoc; - this.createExternalRefs = createExternalRefs; - this.generatePurls = generatePurls; - this.useArtifactID = useArtifactID; - this.includeTransitiveDependencies = includeTransitiveDependencies; - } - - /** - * Adds information about Maven dependencies to the list of SPDX Dependencies - * - * @param mavenProjectBuilder project builder for the repo containing the POM file - * @param session Maven session for building the project - * @param mavenProject Maven project + * Creates an SPDX document from a file + * @param path Path to the SPDX file + * @return an SPDX Spec version 2 document + * @throws IOException on IO Error + * @throws FileNotFoundException if the file does not exist + * @throws InvalidSPDXAnalysisException on invalid SPDX file */ - public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, MavenProject mavenProject, - DependencyNode node, SpdxElement pkg ) throws LicenseMapperException, InvalidSPDXAnalysisException + protected static SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException { - List children = node.getChildren(); - - logDependencies( children ); - - for ( DependencyNode childNode : children ) + ISerializableModelStore modelStore; + OutputFormat of = OutputFormat.getOutputFormat( null, new File( path ) ); + + if (!SpdxMajorVersion.VERSION_2.equals( of.getSpecVersion() )) { + throw new InvalidSPDXAnalysisException( String.format( "Unsupported file type for SPDX Version 2 SPDX documents: %s", of.getSpecVersion().toString() )); + } + if ( of.getArtifactType().equals( "spdx.json" ) ) { - addMavenDependency( pkg, childNode, mavenProjectBuilder, session, mavenProject ); + modelStore = new MultiFormatStore(new InMemSpdxStore(), Format.JSON_PRETTY, Verbose.COMPACT); } - } - - private void addMavenDependency( SpdxElement parentPackage, DependencyNode dependencyNode, ProjectBuilder mavenProjectBuilder, - MavenSession session, MavenProject mavenProject ) - throws LicenseMapperException, InvalidSPDXAnalysisException - { - Artifact dependency = dependencyNode.getArtifact(); - String scope = dependency.getScope(); - RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); - if ( relType == RelationshipType.OTHER ) + else { - LOG.warn( - "Could not determine the SPDX relationship type for dependency artifact ID " + dependency.getArtifactId() + " scope " + scope ); + modelStore = new RdfStore(); } - - SpdxElement dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, mavenProject, useArtifactID ); - - if ( relType.toString().endsWith( "_OF" ) ) + try ( InputStream inputStream = new FileInputStream( path ) ) { - if ( dependencyPackage instanceof SpdxPackage ) - { - this.relationships.computeIfAbsent( parentPackage, key -> new ArrayList<>() ) - .add( spdxDoc.createRelationship( dependencyPackage, relType, - "Relationship created based on Maven POM information" ) ); - LOG.debug( "Added relationship of type " + relType + " for " + dependencyPackage.getName() ); - } - else - { - this.relationships.computeIfAbsent( dependencyPackage, key -> new ArrayList<>() ) - .add( spdxDoc.createRelationship( parentPackage, RelationshipType.OTHER, - "This relationship is the inverse of " + relType + " to an external document reference." ) ); - LOG.debug( "Could not create proper to relationships for external element " + dependencyPackage.getId() ); - } + return (SpdxDocument)modelStore.deSerialize( inputStream, false ); } - else + finally { - this.relationships.computeIfAbsent( parentPackage, key -> new ArrayList<>() ) - .add( spdxDoc.createRelationship( dependencyPackage, relType, - "Relationship based on Maven POM file dependency information" ) ); - } - - if ( includeTransitiveDependencies ) { - addMavenDependencies( mavenProjectBuilder, session, mavenProject, dependencyNode, dependencyPackage ); + if ( modelStore != null ) { + try + { + modelStore.close(); + } + catch ( Exception e ) + { + LOG.error( "Error closing SPDX model store", e ); + } + } } } - - private void logDependencies( List dependencies ) + + /** + * Searched the described packages for the SPDX document for the closest matching package to the artifactId + * @param externalSpdxDoc Doc containing the package + * @param artifactId Maven artifact ID + * @return the closest matching package described by the doc + * @throws InvalidSPDXAnalysisException on SPDX errors + */ + protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument externalSpdxDoc, String artifactId ) throws InvalidSPDXAnalysisException { - if ( !LOG.isDebugEnabled() ) - { - return; - } - LOG.debug( "Dependencies:" ); - if ( dependencies == null ) + SpdxElement itemDescribed = null; + // Find an item described with matching artifact ID + for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) { - LOG.debug( "\tNull dependencies" ); - return; + Optional name = item.getName(); + if ( item instanceof SpdxPackage && name.isPresent() && item.getName().get().equals( artifactId ) ) + { + itemDescribed = item; + break; + } } - if ( dependencies.isEmpty() ) - { - LOG.debug( "\tZero dependencies" ); - return; + if ( itemDescribed == null ) { + // Find the first package + LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in SPDX file." ); + for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) + { + if ( item instanceof SpdxPackage ) + { + itemDescribed = item; + break; + } + } } - for ( DependencyNode node : dependencies ) - { - Artifact dependency = node.getArtifact(); - String filePath = dependency.getFile() != null ? dependency.getFile().getAbsolutePath() : "[NONE]"; - String scope = dependency.getScope() != null ? dependency.getScope() : "[NONE]"; - LOG.debug( - "ArtifactId: " + dependency.getArtifactId() + ", file path: " + filePath + ", Scope: " + scope ); + if ( itemDescribed == null ) { + throw new InvalidSPDXAnalysisException( "SPDX document does not contain any described items." ); } + return (SpdxPackage)itemDescribed; + } + + /** + * Map of namespaces to ExternalDocumentRefs + */ + private Map externalDocuments = new HashMap<>(); + private List documentAnnotations = new ArrayList<>(); + private SpdxDocument spdxDoc; + private SpdxV2LicenseManager licenseManager; + private SpdxV2DocumentBuilder builder; + + /** + * @param builder The document builder + * @param createExternalRefs if true, create external references for dependencies + * @param generatePurls if true, generate a Package URL and include as an external identifier for the dependencies + * @param useArtifactID if true, use the artifact ID for the name of the dependency package, otherwise use the Maven configured project name + * @param includeTransitiveDependencies If true, include transitive dependencies, otherwise include only direct dependencies + */ + public SpdxV2DependencyBuilder( SpdxV2DocumentBuilder builder, boolean createExternalRefs, + boolean generatePurls, boolean useArtifactID, + boolean includeTransitiveDependencies ) + { + super( createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); + this.builder = builder; + this.spdxDoc = builder.getSpdxDoc(); + this.licenseManager = builder.getLicenseManager(); } + @Override + protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode dependencyNode, + ProjectBuilder mavenProjectBuilder, + MavenSession session, MavenProject mavenProject ) + throws LicenseMapperException, InvalidSPDXAnalysisException + { + if ( !(parentPackage instanceof SpdxPackage) ) + { + LOG.error( String.format( "Invalid type for parent package. Expected 'SpdxPackage', found %s", + parentPackage.getClass().getName() ) ); + return; + } + Artifact dependency = dependencyNode.getArtifact(); + String scope = dependency.getScope(); + RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); + if ( relType == RelationshipType.OTHER ) + { + LOG.warn( + "Could not determine the SPDX relationship type for dependency artifact ID " + dependency.getArtifactId() + " scope " + scope ); + } + + SpdxElement dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, + mavenProject, useArtifactID ); + + if ( relType.toString().endsWith( "_OF" ) ) + { + if ( dependencyPackage instanceof SpdxPackage ) + { + ((SpdxPackage)parentPackage).addRelationship( spdxDoc.createRelationship( dependencyPackage, relType, + "Relationship created based on Maven POM information" ) ); + LOG.debug( "Added relationship of type " + relType + " for " + dependencyPackage.getName() ); + } + else + { + ((SpdxPackage)parentPackage).addRelationship(spdxDoc.createRelationship( (SpdxPackage)parentPackage, RelationshipType.OTHER, + "This relationship is the inverse of " + relType + " to an external document reference." ) ); + LOG.debug( "Could not create proper to relationships for external element " + dependencyPackage.getId() ); + } + } + else + { + ((SpdxPackage)parentPackage).addRelationship( spdxDoc.createRelationship( dependencyPackage, relType, + "Relationship based on Maven POM file dependency information" ) ); + } + + if ( includeTransitiveDependencies ) { + addMavenDependencies( mavenProjectBuilder, session, mavenProject, dependencyNode, dependencyPackage ); + } + } + /** * Translate the scope to the SPDX relationship type * * @param scope Maven Dependency Scope (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope) * @param optional True if this is an optional dependency - * @return + * @return SPDX Relationship type based on the scope */ private RelationshipType scopeToRelationshipType( String scope, boolean optional ) { @@ -239,7 +253,80 @@ else if ( scope.equals( "test" ) ) return RelationshipType.OTHER; } } + + /** + * Create an SPDX package from the information in a Maven Project + * + * @param project Maven project + * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used + * @return SPDX Package generated from the metadata in the Maven Project + * @throws IOException On errors reading Maven file information + * @throws SpdxCollectionException On errors with SPDX collections + * @throws NoSuchAlgorithmException if no checksum algorithm was found + * @throws LicenseMapperException on errors mapping or creating SPDX custom licenses + * @throws InvalidSPDXAnalysisException on any other general SPDX errors + */ + private SpdxPackage createSpdxPackage( MavenProject project, boolean useArtifactID ) throws SpdxCollectionException, NoSuchAlgorithmException, LicenseMapperException, InvalidSPDXAnalysisException + { + SpdxDefaultFileInformation fileInfo = new SpdxDefaultFileInformation(); + // initialize the SPDX information from the project + String packageName = project.getName(); + if ( packageName == null || packageName.isEmpty() || useArtifactID ) + { + packageName = project.getGroupId() + ":" + project.getArtifactId(); + } + List contributors = project.getContributors(); + ArrayList fileContributorList = new ArrayList<>(); + if ( contributors != null ) + { + for ( Contributor contributor : contributors ) + { + fileContributorList.add( contributor.getName() ); + } + } + String copyright = "UNSPECIFIED"; + String notice = "UNSPECIFIED"; + String downloadLocation = "NOASSERTION"; + AnyLicenseInfo declaredLicense = mavenLicensesToSpdxLicense( project.getLicenses() ); + fileInfo.setComment( "" ); + fileInfo.setConcludedLicense( "NOASSERTION" ); + fileInfo.setContributors( fileContributorList.toArray( new String[0] ) ); + fileInfo.setCopyright( copyright ); + fileInfo.setDeclaredLicense( declaredLicense.toString() ); + fileInfo.setLicenseComment( "" ); + fileInfo.setNotice( notice ); + + SpdxPackage retval = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), + packageName, new SpdxNoAssertionLicense(), copyright, declaredLicense ) + .setDownloadLocation( downloadLocation ) + .setFilesAnalyzed( false ) + .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) + .build(); + if ( project.getVersion() != null ) + { + retval.setVersionInfo( project.getVersion() ); + } + if ( project.getDescription() != null ) + { + retval.setDescription( project.getDescription() ); + retval.setSummary( project.getDescription() ); + } + if ( project.getOrganization() != null ) + { + retval.setOriginator( SpdxConstantsCompatV2.CREATOR_PREFIX_ORGANIZATION + project.getOrganization().getName() ); + } + if ( project.getUrl() != null ) + { + try { + retval.setHomepage( project.getUrl() ); + } catch ( InvalidSPDXAnalysisException e ) { + LOG.warn( "Invalid homepage for dependency " + project.getArtifactId() + ": " + project.getUrl() ); + } + } + return retval; + } + /** * Create an SPDX Document using the mavenProjectBuilder to resolve properties * including inherited properties @@ -249,8 +336,8 @@ else if ( scope.equals( "test" ) ) * @param mavenProject Maven project * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used * @return SPDX Package build from the MavenProject metadata - * @throws LicenseMapperException - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on errors generating SPDX + * @throws LicenseMapperException on errors mapping licenses or creating custom licenses */ private SpdxElement createSpdxPackage( Artifact artifact, ProjectBuilder mavenProjectBuilder, MavenSession session, @@ -268,7 +355,7 @@ private SpdxElement createSpdxPackage( Artifact artifact, File spdxFile = null; if ( artifact.getFile() != null ) { - spdxFile = artifactFileToSpdxFile( artifact.getFile() ); + spdxFile = artifactFileToSpdxFile( artifact.getFile(), SpdxMajorVersion.VERSION_2 ); } if ( spdxFile != null && spdxFile.exists() ) { @@ -354,7 +441,7 @@ private SpdxElement createSpdxPackage( Artifact artifact, // Name will be the artifact ID LOG.debug( "Dependency " + artifact.getArtifactId() + "Using only artifact information to create dependent package" ); - SpdxPackage pkg = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri() ), + SpdxPackage pkg = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), artifact.getArtifactId(), new SpdxNoAssertionLicense(), "NOASSERTION", new SpdxNoAssertionLicense() ) .setComment( "This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file." ) @@ -365,7 +452,53 @@ private SpdxElement createSpdxPackage( Artifact artifact, .build(); return pkg; } - + + /** + * Create and return an external document reference for an existing package in an SPDX document + * + * @param externalSpdxDoc SPDX Document containing the package to be referenced. + * @param spdxFile SPDX file containing the SPDX document + * @param groupId Group ID for the external artifact + * @param artifactId Artifact ID for the external artifact + * @param version version for the external artifact + * @return created SPDX element + * @throws SpdxCollectionException + * @throws InvalidSPDXAnalysisException + */ + private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpdxDoc, + File spdxFile, + String groupId, + String artifactId, + @Nullable String version ) throws SpdxCollectionException, InvalidSPDXAnalysisException + { + String externalDocNamespace = externalSpdxDoc.getDocumentUri(); + ExternalDocumentRef externalRef = this.externalDocuments.get( externalDocNamespace ); + StringBuilder sb = new StringBuilder( groupId ).append( artifactId ); + if ( Objects.nonNull( version )) { + sb.append( version ); + } + String fullArtifactId = sb.toString(); + if ( externalRef == null ) + { + String externalRefDocId = SpdxConstantsCompatV2.EXTERNAL_DOC_REF_PRENUM + fixExternalRefId( fullArtifactId ); + LOG.debug( "Creating external document ref " + externalDocNamespace ); + Checksum cksum = (Checksum)SpdxFileCollector.generateSha1( spdxFile, builder ); + externalRef = spdxDoc.createExternalDocumentRef( externalRefDocId, externalSpdxDoc.getDocumentUri(), cksum ); + spdxDoc.getExternalDocumentRefs().add( externalRef ); + org.spdx.library.model.v2.Annotation docRefAddedAnnotation = spdxDoc.createAnnotation( "Tool: spdx-maven-plugin", + AnnotationType.OTHER, + format.format( new Date() ), + "External document ref '"+externalRefDocId+"' created for artifact "+fullArtifactId ); + spdxDoc.getAnnotations().add( docRefAddedAnnotation ); + this.documentAnnotations.add( docRefAddedAnnotation ); + this.externalDocuments.put( externalDocNamespace, externalRef ); + LOG.debug( "Created external document ref " + externalRefDocId ); + } + SpdxPackage pkg = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); + return new ExternalSpdxElement( spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), + externalRef.getId() + ":" + pkg.getId(), spdxDoc.getCopyManager(), true ); + } + /** * Copies the closest matching described package in the externalSpdxDoc to the returned element * @param externalSpdxDoc @@ -381,7 +514,7 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc SpdxPackage source = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); Optional downloadLocation = source.getDownloadLocation(); Optional name = source.getName(); - SpdxPackage dest = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri()), + SpdxPackage dest = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), name.isPresent() ? name.get() : "NONE", source.getLicenseConcluded(), source.getCopyrightText(), source.getLicenseDeclared() ) .setFilesAnalyzed( false ) @@ -464,238 +597,7 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc } return dest; } - - /** - * Searched the described packages for the SPDX document for the closest matching package to the artifactId - * @param externalSpdxDoc Doc containing the package - * @param artifactId Maven artifact ID - * @return the closest matching package described by the doc - * @throws InvalidSPDXAnalysisException - */ - private SpdxPackage findMatchingDescribedPackage( SpdxDocument externalSpdxDoc, String artifactId ) throws InvalidSPDXAnalysisException - { - SpdxElement itemDescribed = null; - // Find an item described with matching artifact ID - for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) - { - Optional name = item.getName(); - if ( item instanceof SpdxPackage && name.isPresent() && item.getName().get().equals( artifactId ) ) - { - itemDescribed = item; - break; - } - } - if ( itemDescribed == null ) { - // Find the first package - LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in SPDX file." ); - for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) - { - if ( item instanceof SpdxPackage ) - { - itemDescribed = item; - break; - } - } - } - if ( itemDescribed == null ) { - throw new InvalidSPDXAnalysisException( "SPDX document does not contain any described items." ); - } - return (SpdxPackage)itemDescribed; - } - - /** - * Creates an SPDX document from a file - * @param path Path to the SPDX file - * @return - * @throws IOException - * @throws FileNotFoundException - * @throws InvalidSPDXAnalysisException - */ - private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException - { - ISerializableModelStore modelStore; - if ( path.toLowerCase().endsWith( "json" ) ) - { - modelStore = new MultiFormatStore(new InMemSpdxStore(), Format.JSON_PRETTY, Verbose.COMPACT); - } - else - { - modelStore = new RdfStore(); - } - try ( InputStream inputStream = new FileInputStream( path ) ) - { - String documentUri = modelStore.deSerialize( inputStream, false ); - return new SpdxDocument(modelStore, documentUri, spdxDoc.getCopyManager(), false); - } - finally - { - if ( modelStore != null ) { - try - { - modelStore.close(); - } - catch ( Exception e ) - { - LOG.error( "Error closing SPDX model store", e ); - } - } - } - } - - /** - * Create and return an external document reference for an existing package in an SPDX document - * - * @param externalSpdxDoc SPDX Document containing the package to be referenced. - * @param spdxFile SPDX file containing the SPDX document - * @param groupId Group ID for the external artifact - * @param artifactId Artifact ID for the external artifact - * @param version version for the external artifact - * @return created SPDX element - * @throws SpdxCollectionException - * @throws InvalidSPDXAnalysisException - */ - private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpdxDoc, - File spdxFile, - String groupId, - String artifactId, - @Nullable String version ) throws SpdxCollectionException, InvalidSPDXAnalysisException - { - String externalDocNamespace = externalSpdxDoc.getDocumentUri(); - ExternalDocumentRef externalRef = this.externalDocuments.get( externalDocNamespace ); - StringBuilder sb = new StringBuilder( groupId ).append( artifactId ); - if ( Objects.nonNull( version )) { - sb.append( version ); - } - String fullArtifactId = sb.toString(); - if ( externalRef == null ) - { - String externalRefDocId = SpdxConstants.EXTERNAL_DOC_REF_PRENUM + fixExternalRefId( fullArtifactId ); - LOG.debug( "Creating external document ref " + externalDocNamespace ); - String sha1 = SpdxFileCollector.generateSha1( spdxFile, spdxDoc ); - Checksum cksum = externalSpdxDoc.createChecksum( ChecksumAlgorithm.SHA1, sha1 ); - externalRef = spdxDoc.createExternalDocumentRef( externalRefDocId, externalSpdxDoc.getDocumentUri(), cksum ); - spdxDoc.getExternalDocumentRefs().add( externalRef ); - org.spdx.library.model.Annotation docRefAddedAnnotation = spdxDoc.createAnnotation( "Tool: spdx-maven-plugin", - AnnotationType.OTHER, - format.format( new Date() ), - "External document ref '"+externalRefDocId+"' created for artifact "+fullArtifactId ); - spdxDoc.getAnnotations().add( docRefAddedAnnotation ); - this.documentAnnotations.add( docRefAddedAnnotation ); - this.externalDocuments.put( externalDocNamespace, externalRef ); - LOG.debug( "Created external document ref " + externalRefDocId ); - } - SpdxPackage pkg = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); - return new ExternalSpdxElement( spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), - externalRef.getId() + ":" + pkg.getId(), spdxDoc.getCopyManager(), true ); - } - - /** - * Make an external document reference ID valid by replacing any invalid characters with dashes - * - * @param externalRefId - * @return - */ - private String fixExternalRefId( String externalRefId ) - { - StringBuilder sb = new StringBuilder(); - for ( int i = 0; i < externalRefId.length(); i++ ) - { - if ( validExternalRefIdChar( externalRefId.charAt( i ) ) ) - { - sb.append( externalRefId.charAt( i ) ); - } - else - { - sb.append( "-" ); - } - } - return sb.toString(); - } - - - /** - * @param ch character to test - * @return true if the character is valid for use in an External Reference ID - */ - private boolean validExternalRefIdChar( char ch ) - { - return ( ( ch >= 'a' && ch <= 'z' ) || ( ch >= 'A' && ch <= 'Z' ) || ( ch >= '0' && ch <= '9' ) || ch == '.' || ch == '-' ); - } - - /** - * Create an SPDX package from the information in a Maven Project - * - * @param project Maven project - * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used - * @return SPDX Package generated from the metadata in the Maven Project - * @throws XmlPullParserException - * @throws IOException - * @throws SpdxCollectionException - * @throws NoSuchAlgorithmException - * @throws LicenseMapperException - * @throws InvalidSPDXAnalysisException - */ - private SpdxPackage createSpdxPackage( MavenProject project, boolean useArtifactID ) throws SpdxCollectionException, NoSuchAlgorithmException, LicenseMapperException, InvalidSPDXAnalysisException - { - SpdxDefaultFileInformation fileInfo = new SpdxDefaultFileInformation(); - - // initialize the SPDX information from the project - String packageName = project.getName(); - if ( packageName == null || packageName.isEmpty() || useArtifactID ) - { - packageName = project.getGroupId() + ":" + project.getArtifactId(); - } - List contributors = project.getContributors(); - ArrayList fileContributorList = new ArrayList<>(); - if ( contributors != null ) - { - for ( Contributor contributor : contributors ) - { - fileContributorList.add( contributor.getName() ); - } - } - String copyright = "UNSPECIFIED"; - String notice = "UNSPECIFIED"; - String downloadLocation = "NOASSERTION"; - AnyLicenseInfo declaredLicense = mavenLicensesToSpdxLicense( project.getLicenses() ); - fileInfo.setComment( "" ); - fileInfo.setConcludedLicense( new SpdxNoAssertionLicense() ); - fileInfo.setContributors( fileContributorList.toArray( new String[0] ) ); - fileInfo.setCopyright( copyright ); - fileInfo.setDeclaredLicense( declaredLicense ); - fileInfo.setLicenseComment( "" ); - fileInfo.setNotice( notice ); - - SpdxPackage retval = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri() ), - packageName, new SpdxNoAssertionLicense(), copyright, declaredLicense ) - .setDownloadLocation( downloadLocation ) - .setFilesAnalyzed( false ) - .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) - .build(); - if ( project.getVersion() != null ) - { - retval.setVersionInfo( project.getVersion() ); - } - if ( project.getDescription() != null ) - { - retval.setDescription( project.getDescription() ); - retval.setSummary( project.getDescription() ); - } - if ( project.getOrganization() != null ) - { - retval.setOriginator( SpdxConstants.CREATOR_PREFIX_ORGANIZATION + project.getOrganization().getName() ); - } - if ( project.getUrl() != null ) - { - try { - retval.setHomepage( project.getUrl() ); - } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( "Invalid homepage for dependency " + project.getArtifactId() + ": " + project.getUrl() ); - } - } - return retval; - } - + /** * Convert a list of Maven licenses to an SPDX License * @@ -717,133 +619,8 @@ private AnyLicenseInfo mavenLicensesToSpdxLicense( List mavenLicenses ) } catch ( LicenseManagerException ex ) { - return MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( mavenLicenses, spdxDoc ); - } - - } - - /** - * Get filsets of files included in the project from the Maven model - * - * @param model Maven model - * @return Source file set and resource filesets - */ - @SuppressWarnings( "unused" ) - private FileSet[] getIncludedDirectoriesFromModel( Model model ) - { - //TODO: This can be refactored to common code from the CreateSpdxMojo - ArrayList result = new ArrayList<>(); - String sourcePath = model.getBuild().getSourceDirectory(); - if ( sourcePath != null && !sourcePath.isEmpty() ) - { - FileSet srcFileSet = new FileSet(); - File sourceDir = new File( sourcePath ); - srcFileSet.setDirectory( sourceDir.getAbsolutePath() ); - srcFileSet.addInclude( CreateSpdxMojo.INCLUDE_ALL ); - result.add( srcFileSet ); - } - - List resourceList = model.getBuild().getResources(); - if ( resourceList != null ) - { - for ( Resource resource : resourceList ) - { - FileSet resourceFileSet = new FileSet(); - File resourceDir = new File( resource.getDirectory() ); - resourceFileSet.setDirectory( resourceDir.getAbsolutePath() ); - resourceFileSet.setExcludes( resource.getExcludes() ); - resourceFileSet.setIncludes( resource.getIncludes() ); - result.add( resourceFileSet ); - } + return MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( mavenLicenses, spdxDoc ); } - return result.toArray( new FileSet[0] ); - } - /** - * Converts an artifact file to an SPDX file - * - * @param file input file - * @return SPDX file using the SPDX naming conventions - */ - private File artifactFileToSpdxFile( File file ) - { - File retval = getFileWithDifferentType( file, "spdx.rdf.xml" ); - if ( retval == null || !retval.exists() ) - { - retval = getFileWithDifferentType( file, "spdx.json" ); - } - if ( retval == null || !retval.exists() ) - { - retval = getFileWithDifferentType( file, "spdx" ); - } - return retval; - } - - /** - * Convert a file to a different type (e.g. file.txt -> file.rdf with a type rdf parameter) - * - * @param file Input file - * @param type Type to change to - * @return New file type with only the type changed - */ - private File getFileWithDifferentType( File file, String type ) - { - String filePath = file.getAbsolutePath(); - int indexOfDot = filePath.lastIndexOf( '.' ); - if ( indexOfDot > 0 ) - { - filePath = filePath.substring( 0, indexOfDot + 1 ); - } - filePath = filePath + type; - File retval = new File( filePath ); - return retval; - } - - /** - * @return All external document references used by any dependency toRelationships - */ - public Collection getDocumentExternalReferences() - { - return this.externalDocuments.values(); - } - - /** - * @return the relationships - */ - public Map> getRelationships() - { - return relationships; - } - - /** - * @return the externalDocuments - */ - public Map getExternalDocuments() - { - return externalDocuments; - } - - /** - * @return the documentAnnotations - */ - public List getDocumentAnnotations() - { - return documentAnnotations; - } - - /** - * @return the spdxDoc - */ - public SpdxDocument getSpdxDoc() - { - return spdxDoc; - } - - /** - * @return the createExternalRefs - */ - public boolean isCreateExternalRefs() - { - return createExternalRefs; } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java deleted file mode 100644 index c236ed1..0000000 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyInformation.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2024 Source Auditor Inc. - */ -package org.spdx.maven.utils; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.shared.dependency.graph.DependencyNode; - -/** - * @author gary - * - */ -public class SpdxV2DependencyInformation - extends AbstractDependencyInformation -{ - - /** - * @param builer - * @param createExternalRefs - * @param generatePurls - * @param useArtifactID - * @param includeTransitiveDependencies - */ - public SpdxV2DependencyInformation( SpdxV2DocumentBuilder builer, boolean createExternalRefs, - boolean generatePurls, boolean useArtifactID, - boolean includeTransitiveDependencies ) - { - // TODO Auto-generated constructor stub - } - - @Override - public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, - MavenProject mavenProject, DependencyNode parentNode, Object projectPackage ) - { - // TODO Auto-generated method stub - - } - -} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java index 8c3bb87..914f66d 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -5,25 +5,58 @@ package org.spdx.maven.utils; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.net.URI; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.Set; import org.apache.maven.model.License; +import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.model.fileset.FileSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.spdx.core.CoreModelObject; import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.jacksonstore.MultiFormatStore; import org.spdx.jacksonstore.MultiFormatStore.Format; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.ListedLicenses; import org.spdx.library.ModelCopyManager; +import org.spdx.library.model.v2.Annotation; +import org.spdx.library.model.v2.ExternalRef; +import org.spdx.library.model.v2.ReferenceType; +import org.spdx.library.model.v2.Relationship; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.SpdxCreatorInformation; import org.spdx.library.model.v2.SpdxDocument; import org.spdx.library.model.v2.SpdxModelFactoryCompatV2; -import org.spdx.library.model.v2.license.ExtractedLicenseInfo; +import org.spdx.library.model.v2.SpdxPackage; +import org.spdx.library.model.v2.SpdxPackageVerificationCode; +import org.spdx.library.model.v2.SpdxVerificationHelper; +import org.spdx.library.model.v2.enumerations.ReferenceCategory; +import org.spdx.library.model.v2.enumerations.RelationshipType; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.SpdxListedLicense; +import org.spdx.library.referencetype.ListedReferenceTypes; +import org.spdx.library.model.v2.enumerations.AnnotationType; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.Purpose; +import org.spdx.maven.Checksum; +import org.spdx.maven.ExternalReference; import org.spdx.maven.NonStandardLicense; import org.spdx.maven.OutputFormat; +import org.spdx.maven.Packaging; import org.spdx.spdxRdfStore.RdfStore; +import org.spdx.storage.IModelStore.IdType; import org.spdx.storage.simple.InMemSpdxStore; /** @@ -35,9 +68,11 @@ public class SpdxV2DocumentBuilder extends AbstractDocumentBuilder { + private static final Logger LOG = LoggerFactory.getLogger( SpdxV2DocumentBuilder.class ); protected SpdxDocument spdxDoc; protected SpdxV2LicenseManager licenseManager; + protected SpdxPackage projectPackage; /** * @param mavenProject Maven project @@ -74,76 +109,415 @@ public SpdxV2DocumentBuilder( MavenProject mavenProject, boolean generatePurls, licenseManager = new SpdxV2LicenseManager( spdxDoc, useStdLicenseSourceUrls ); } - @Override - public CoreModelObject getSpdxDoc() + /** + * @return the SPDX Document + */ + public SpdxDocument getSpdxDoc() { return this.spdxDoc; } @Override - public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) + public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) throws SpdxBuilderException { - // TODO Auto-generated method stub + try + { + // document comment + if ( projectInformation.getDocumentComment() != null && !projectInformation.getDocumentComment().isEmpty() ) + { + spdxDoc.setComment( projectInformation.getDocumentComment() ); + } + // creator + fillCreatorInfo( projectInformation ); + // data license + SpdxListedLicense dataLicense = LicenseInfoFactory.getListedLicenseByIdCompatV2( SpdxConstantsCompatV2.SPDX_DATA_LICENSE_ID ); + spdxDoc.setDataLicense( dataLicense ); + // annotations + if ( projectInformation.getDocumentAnnotations() != null && projectInformation.getDocumentAnnotations().length > 0 ) + { + spdxDoc.setAnnotations( toSpdxAnnotations( projectInformation.getDocumentAnnotations() ) ); + } + spdxDoc.setName( projectInformation.getName() ); // Same as package name + // Package level information + projectPackage = createSpdxPackage( projectInformation ); + Relationship documentContainsRelationship = spdxDoc.createRelationship( projectPackage, RelationshipType.DESCRIBES, "" ); + spdxDoc.addRelationship( documentContainsRelationship ); + } + catch ( InvalidSPDXAnalysisException | MojoExecutionException e ) + { + throw new SpdxBuilderException( "Error adding package information to SPDX document", e ); + } + } + + private Collection toSpdxAnnotations( org.spdx.maven.Annotation[] annotations ) throws MojoExecutionException + { + List retval = new ArrayList<>(); + for ( org.spdx.maven.Annotation annotation: annotations ) + { + + AnnotationType annotationType = AnnotationType.OTHER; + try + { + annotationType = AnnotationType.valueOf( annotation.getAnnotationType() ); + } + catch ( Exception ex ) + { + throw new MojoExecutionException( "Invalid annotation type "+annotation.getAnnotationType() ); + } + try + { + retval.add( spdxDoc.createAnnotation( annotation.getAnnotator(), + annotationType, + annotation.getAnnotationDate(), + annotation.getAnnotationComment() ) ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error creating annotation.", e ); + } + } + return retval; + } + + /** + * Fill in the creator information to the SPDX document + * + * @param projectInformation project level information including the creators + * @throws InvalidSPDXAnalysisException + */ + private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws InvalidSPDXAnalysisException + { + ArrayList creators = new ArrayList<>(); + String[] parameterCreators = projectInformation.getCreators(); + for ( String parameterCreator : parameterCreators ) + { + String verify = SpdxVerificationHelper.verifyCreator( parameterCreator ); + if ( verify == null ) + { + creators.add( parameterCreator ); + } + else + { + LOG.warn( + "Invalid creator string ( " + verify + " ), " + parameterCreator + " will be skipped." ); + } + } + SpdxCreatorInformation spdxCreator = spdxDoc.createCreationInfo( creators, format.format( new Date() ) ); + spdxCreator.setComment( projectInformation.getCreatorComment() ); + spdxCreator.setLicenseListVersion( ListedLicenses.getListedLicenses().getLicenseListVersion() ); + spdxDoc.setCreationInfo( spdxCreator ); + } + + private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation ) throws SpdxBuilderException + { + String copyrightText = projectInformation.getCopyrightText(); + if ( copyrightText == null ) + { + copyrightText = UNSPECIFIED; + } + String downloadUrl = null; + + if ( SpdxVerificationHelper.isValidUri( projectInformation.getDownloadUrl() )) + { + downloadUrl = projectInformation.getDownloadUrl(); + } + else + { + LOG.warn( "Invalid download location in POM file: " + projectInformation.getDownloadUrl() ); + } + if ( downloadUrl == null ) + { + downloadUrl = UNSPECIFIED; + } + SpdxPackageVerificationCode nullPackageVerificationCode; + try + { + nullPackageVerificationCode = spdxDoc.createPackageVerificationCode( NULL_SHA1, new ArrayList() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error creating null package verification code", e ); + } + SpdxPackage pkg; + try + { + final AnyLicenseInfo concludedLicense = LicenseInfoFactory + .parseSPDXLicenseStringCompatV2( projectInformation.getConcludedLicense(), spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); + final AnyLicenseInfo declaredLicense = LicenseInfoFactory + .parseSPDXLicenseStringCompatV2( projectInformation.getDeclaredLicense(), spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); + final Packaging packaging = Packaging.valueOfPackaging( project.getPackaging() ); + final Purpose primaryPurpose = packaging != null ? packaging.getV2Purpose() : Purpose.LIBRARY; + pkg = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), + projectInformation.getName(), concludedLicense, + copyrightText, declaredLicense ) + .setDownloadLocation( downloadUrl ) + .setPackageVerificationCode( nullPackageVerificationCode ) + .setPrimaryPurpose( primaryPurpose ) + .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error creating initial package", e ); + } + // Annotations + if ( projectInformation.getPackageAnnotations() != null && projectInformation.getPackageAnnotations().length > 0 ) + { + try + { + pkg.setAnnotations( toSpdxAnnotations( projectInformation.getPackageAnnotations() ) ); + } + catch ( InvalidSPDXAnalysisException | MojoExecutionException e ) + { + throw new SpdxBuilderException( "Error adding package annotations to SPDX document", e ); + } + } + try + { + // description + if ( projectInformation.getDescription() != null ) + { + pkg.setDescription( projectInformation.getDescription() ); + } + // download url + if ( projectInformation.getDownloadUrl() != null ) + { + pkg.setDownloadLocation( projectInformation.getDownloadUrl() ); + } + // archive file name + if ( projectInformation.getPackageArchiveFileName() != null ) + { + pkg.setPackageFileName( projectInformation.getPackageArchiveFileName() ); + } + // home page + if ( projectInformation.getHomePage() != null ) + { + try + { + pkg.setHomepage( projectInformation.getHomePage() ); + } + catch( InvalidSPDXAnalysisException ex ) + { + LOG.warn( "Invalid URL in project POM file: "+projectInformation.getHomePage() ); + } + + } + // source information + if ( projectInformation.getSourceInfo() != null ) + { + pkg.setSourceInfo( projectInformation.getSourceInfo() ); + } + // license comment + if ( projectInformation.getLicenseComment() != null ) + { + pkg.setLicenseComments( projectInformation.getLicenseComment() ); + } + // originator + if ( projectInformation.getOriginator() != null ) + { + pkg.setOriginator( projectInformation.getOriginator() ); + } + // short description + if ( projectInformation.getShortDescription() != null ) + { + pkg.setSummary( projectInformation.getShortDescription() ); + } + // supplier + if ( projectInformation.getSupplier() != null ) + { + pkg.setSupplier( projectInformation.getSupplier() ); + } + // version info + if ( projectInformation.getVersionInfo() != null ) + { + pkg.setVersionInfo( projectInformation.getVersionInfo() ); + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error adding package properties", e ); + } + // sha1 checksum + if ( projectInformation.getChecksums() != null ) + { + try + { + for ( Checksum checksum : projectInformation.getChecksums() ) + { + final ChecksumAlgorithm algorithm = ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ); + if ( Objects.isNull( algorithm )) + { + LOG.error( String.format( "Invalid checksum algorithm %s", checksum.getAlgorithm() ) ); + } + else + { + pkg.getChecksums().add( spdxDoc.createChecksum( algorithm, checksum.getValue() )); + } + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( + "Error adding package information to SPDX document - Invalid checksum provided", e ); + } + } + // external references + ExternalReference[] externalRefs = projectInformation.getExternalRefs(); + if ( externalRefs != null && externalRefs.length > 0 ) + { + for ( ExternalReference externalRef : externalRefs ) + { + try + { + pkg.getExternalRefs().add( convertExternalRef( externalRef ) ); + } + catch ( MojoExecutionException | InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( + "Error adding package information to SPDX document - Invalid external refs provided", e ); + } + } + } + return pkg; } @Override - public void collectSpdxFileInformation( List sources, String absolutePath, + public void collectSpdxFileInformation( List sources, String baseDir, SpdxDefaultFileInformation defaultFileInformation, HashMap pathSpecificInformation, - Set checksumAlgorithms ) + Set checksumAlgorithms ) throws SpdxBuilderException { - // TODO Auto-generated method stub - + SpdxV2FileCollector fileCollector = new SpdxV2FileCollector(); + try + { + fileCollector.collectFiles( sources, baseDir, defaultFileInformation, + pathSpecificInformation, projectPackage, RelationshipType.GENERATES, spdxDoc, checksumAlgorithms ); + projectPackage.getFiles().addAll( fileCollector.getFiles() ); + projectPackage.getLicenseInfoFromFiles().addAll( fileCollector.getLicenseInfoFromFiles() ); + } + catch ( SpdxCollectionException|InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error collecting SPDX file information", e ); + } + try + { + String spdxFileName = spdxFile.getPath().replace( "\\", "/" ); + projectPackage.setPackageVerificationCode( fileCollector.getVerificationCode( spdxFileName, spdxDoc ) ); + } + catch ( NoSuchAlgorithmException e ) + { + throw new SpdxBuilderException( "Unable to calculate verification code", e ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Unable to update verification code", e ); + } } @Override - public SpdxV2LicenseManager getLicenseManager() + public void saveSpdxDocumentToFile() throws SpdxBuilderException { - // TODO Auto-generated method stub - return null; + try ( FileOutputStream spdxOut = new FileOutputStream( spdxFile ) ) + { + modelStore.serialize( spdxOut ); + } + catch ( FileNotFoundException e ) + { + throw new SpdxBuilderException( "Error saving SPDX data to file", e ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error collecting SPDX file data", e ); + } + catch ( IOException e ) + { + throw new SpdxBuilderException( "I/O Error saving SPDX data to file", e ); + } } @Override - public void addDependencyInformation( AbstractDependencyInformation dependencyInformation ) + public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException { - // TODO Auto-generated method stub - + if ( nonStandardLicenses != null ) + { + for ( NonStandardLicense nonStandardLicense : nonStandardLicenses ) + { + try + { + // the following will add the non-standard license to the document container + licenseManager.addExtractedLicense( nonStandardLicense ); + } + catch ( LicenseManagerException e ) + { + throw new SpdxBuilderException( "Error adding non standard license", e ); + } + } + } } - - @Override - public void saveSpdxDocumentToFile() + + public ExternalRef convertExternalRef( ExternalReference externalReference ) throws MojoExecutionException { - // TODO Auto-generated method stub - + ReferenceCategory cat = null; + + try { + cat = ReferenceCategory.valueOf( externalReference.getCategory().replaceAll( "-", "_" ) ); + } + catch ( Exception ex ) + { + throw new MojoExecutionException("External reference category " + externalReference.getCategory() + " is not recognized as a valid, standard category." ); + } + ReferenceType refType = null; + try + { + refType = ListedReferenceTypes.getListedReferenceTypes().getListedReferenceTypeByName( externalReference.getType() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error getting listed reference type for " + externalReference.getType(), e ); + } + if ( refType == null ) + { + throw new MojoExecutionException( "Listed reference type not found for " + externalReference.getType() ); + } + try + { + return spdxDoc.createExternalRef( cat, refType, externalReference.getLocator(), externalReference.getComment() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error creating External Reference", e ); + } } @Override - public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) + public CoreModelObject getProjectPackage() { // TODO Auto-generated method stub - + return null; } @Override - public Object getProjectPackage() + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) { // TODO Auto-generated method stub return null; } @Override - public Object createChecksum( String algorithm, String checksum ) + public List verify() { - // TODO Auto-generated method stub - return null; + return spdxDoc.verify(); } - - @Override - public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + + /** + * @return the license manager + */ + public SpdxV2LicenseManager getLicenseManager() { - // TODO Auto-generated method stub - return null; + return this.licenseManager; } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java new file mode 100644 index 0000000..9ed96d1 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -0,0 +1,700 @@ +/* + * Copyright 2014 Source Auditor Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.Map.Entry; + +import org.apache.maven.shared.model.fileset.FileSet; +import org.apache.maven.shared.model.fileset.util.FileSetManager; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.model.v2.Relationship; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxFile; +import org.spdx.library.model.v2.SpdxPackage; +import org.spdx.library.model.v2.SpdxPackageVerificationCode; +import org.spdx.library.model.v2.SpdxSnippet; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.FileType; +import org.spdx.library.model.v2.enumerations.RelationshipType; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.InvalidLicenseStringException; +import org.spdx.maven.Checksum; +import org.spdx.maven.SnippetInfo; +import org.spdx.storage.IModelStore.IdType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Collects SPDX file information from directories. + *

+ * The method collectFilesInDirectory(FileSet[] filesets) will scan and create SPDX File information for + * all files in the filesets. + * + * @author Gary O'Neall + */ +public class SpdxV2FileCollector +{ + private static final Logger LOG = LoggerFactory.getLogger( SpdxV2FileCollector.class ); + + // constants for mapping extensions to types. + static final String SPDX_FILE_TYPE_CONSTANTS_PROP_PATH = "resources/SpdxFileTypeConstants.prop"; + + static final Map EXT_TO_FILE_TYPE = new HashMap<>(); + + static + { + loadFileExtensionConstants(); + } + + static final Map checksumAlgorithms = new HashMap<>(); + + static + { + checksumAlgorithms.put( ChecksumAlgorithm.SHA1.toString(), "SHA-1" ); + checksumAlgorithms.put( ChecksumAlgorithm.SHA224.toString(), "SHA-224" ); + checksumAlgorithms.put( ChecksumAlgorithm.SHA256.toString(), "SHA-256" ); + checksumAlgorithms.put( ChecksumAlgorithm.SHA384.toString(), "SHA-384" ); + checksumAlgorithms.put( ChecksumAlgorithm.SHA3_384.toString(), "SHA-512" ); + checksumAlgorithms.put( ChecksumAlgorithm.MD2.toString(), "MD2" ); + checksumAlgorithms.put( ChecksumAlgorithm.MD4.toString(), "MD4" ); + checksumAlgorithms.put( ChecksumAlgorithm.MD5.toString(), "MD5" ); + checksumAlgorithms.put( ChecksumAlgorithm.MD6.toString(), "MD6" ); + } + + Set licensesFromFiles = new HashSet<>(); + /** + * Map of fileName, SPDXFile for all files in the SPDX document + */ + Map spdxFiles = new HashMap<>(); + List spdxSnippets = new ArrayList<>(); + + FileSetManager fileSetManager = new FileSetManager(); + + /** + * SpdxFileCollector collects SPDX file information for files + */ + public SpdxV2FileCollector() + { + } + + /** + * Load file type constants from the properties file + */ + private static void loadFileExtensionConstants() + { + Properties prop = new Properties(); + try ( InputStream is = SpdxV2FileCollector.class.getClassLoader().getResourceAsStream( + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ) ) + { + if ( is == null ) + { + LOG.error( "Unable to load properties file " + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ); + return; + } + prop.load( is ); + Iterator> iter = prop.entrySet().iterator(); + while ( iter.hasNext() ) + { + Entry entry = iter.next(); + String fileTypeStr = (String)entry.getKey(); + FileType fileType = FileType.valueOf( fileTypeStr ); + String[] extensions = ((String)entry.getValue()).split( "," ); + for ( String extension:extensions ) + { + try + { + String trimmedExtension = extension.toUpperCase().trim(); + if ( EXT_TO_FILE_TYPE.containsKey( trimmedExtension ) ) + { + LOG.warn( "Duplicate file extension: "+trimmedExtension ); + } + EXT_TO_FILE_TYPE.put( trimmedExtension, fileType ); + } + catch ( Exception ex ) { + LOG.error( "Error adding file extensions to filetype map", ex ); + } + } + } + } + catch ( IOException e ) + { + LOG.warn( + "WARNING: Error reading SpdxFileTypeConstants properties file. All file types will be mapped to Other." ); + } + } + + /** + * Collect file information in the directory (including subdirectories). + * + * @param fileSets FileSets containing the description of the directory to be scanned + * @param baseDir project base directory used to construct the relative paths for the SPDX files + * @param defaultFileInformation Information on default SPDX field data for the files + * @param pathSpecificInformation Map of path to file information used to override the default file information + * @param relationshipType Type of relationship to the project package + * @param projectPackage Package to which the files belong + * @param spdxDoc SPDX document which contains the extracted license infos that may be needed for license parsing + * + * @throws SpdxCollectionException + */ + public void collectFiles( List fileSets, String baseDir, + SpdxDefaultFileInformation defaultFileInformation, + Map pathSpecificInformation, + SpdxPackage projectPackage, RelationshipType relationshipType, + SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException + { + for ( FileSet fileSet : fileSets ) + { + String[] includedFiles = fileSetManager.getIncludedFiles( fileSet ); + for ( String includedFile : includedFiles ) + { + String filePath = fileSet.getDirectory() + File.separator + includedFile; + File file = new File( filePath ); + String relativeFilePath = file.getAbsolutePath().substring( baseDir.length() + 1 ).replace( '\\', '/' ); + SpdxDefaultFileInformation fileInfo = findDefaultFileInformation( relativeFilePath, + pathSpecificInformation ); + if ( fileInfo == null ) + { + fileInfo = defaultFileInformation; + } + + String outputFileName; + if ( fileSet.getOutputDirectory() != null ) + { + outputFileName = fileSet.getOutputDirectory() + File.separator + includedFile; + } + else + { + outputFileName = file.getAbsolutePath().substring( baseDir.length() + 1 ); + } + collectFile( file, outputFileName, fileInfo, relationshipType, projectPackage, spdxDoc, algorithms ); + } + } + } + + /** + * Find the most appropriate file information based on the lowest level match (closed to file) + * + * @param filePath + * @param pathSpecificInformation + * @return + */ + private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, Map pathSpecificInformation ) + { + LOG.debug( "Checking for file path " + filePath ); + SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); + if ( retval != null ) + { + LOG.debug( "Found filepath" ); + return retval; + } + // see if any of the parent directories contain default information which should be used + String parentPath = filePath; + int parentPathIndex = 0; + do + { + parentPathIndex = parentPath.lastIndexOf( "/" ); + if ( parentPathIndex > 0 ) + { + parentPath = parentPath.substring( 0, parentPathIndex ); + retval = pathSpecificInformation.get( parentPath ); + } + } while ( retval == null && parentPathIndex > 0 ); + if ( retval != null ) + { + LOG.debug( "Found directory containing file path for path specific information. File path: " + parentPath ); + } + return retval; + } + + /** + * Collect SPDX information for a specific file + * + * @param file + * @param outputFileName Path to the output file name relative to the root of the output archive file + * @param relationshipType Type of relationship to the project package + * @param projectPackage Package to which the files belong + * @param spdxDoc SPDX Document which will contain the files + * @param algorithms algorithms to use to generate checksums + * @throws SpdxCollectionException + */ + private void collectFile( File file, String outputFileName, SpdxDefaultFileInformation fileInfo, + RelationshipType relationshipType, SpdxPackage projectPackage, + SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException + { + if ( spdxFiles.containsKey( file.getPath() ) ) + { + return; // already added from a previous scan + } + SpdxFile spdxFile = convertToSpdxFile( file, outputFileName, fileInfo, algorithms, spdxDoc ); + try + { + Relationship relationship = spdxDoc.createRelationship( projectPackage, relationshipType, "" ); + spdxFile.addRelationship( relationship ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file relationship", e ); + } + if ( fileInfo.getSnippets() != null ) + { + for ( SnippetInfo snippet : fileInfo.getSnippets() ) + { + SpdxSnippet spdxSnippet; + try + { + spdxSnippet = convertToSpdxSnippet( snippet, spdxFile, spdxDoc ); + } + catch ( InvalidLicenseStringException e ) + { + throw new SpdxCollectionException( + "Error processing SPDX snippet information. Invalid license string specified in snippet.", + e ); + } + catch ( SpdxBuilderException e ) + { + throw new SpdxCollectionException( "Error creating SPDX snippet information.", e ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( + "Error processing SPDX snippet information.", + e ); + } + spdxSnippets.add( spdxSnippet ); + } + } + spdxFiles.put( file.getPath(), spdxFile ); + Collection licenseInfoFromFiles; + try + { + licenseInfoFromFiles = spdxFile.getLicenseInfoFromFiles(); + licensesFromFiles.addAll( licenseInfoFromFiles ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error getting license information from files.", e ); + } + } + + /** + * Create an SpdxSnippet from the snippet information provided + * @param snippet + * @param spdxFile + * @param spdxDoc + * @return + * @throws SpdxBuilderException + * @throws InvalidSPDXAnalysisException + */ + private SpdxSnippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile, SpdxDocument spdxDoc ) throws SpdxBuilderException, InvalidSPDXAnalysisException + { + //TODO: Add annotations to snippet + return spdxDoc.createSpdxSnippet( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), + snippet.getName(), snippet.getLicenseConcluded( spdxDoc ), + snippet.getLicenseInfoInSnippet( spdxDoc ), + snippet.getCopyrightText(), spdxFile, + snippet.getByteRangeStart(), snippet.getByteRangeEnd() ) + .setComment( snippet.getComment() ) + .setLicenseComments( snippet.getLicensComment() ) + .setLineRange( snippet.getLineRangeStart(), snippet.getLineRangeEnd() ) + .build(); + } + + /** + * @param file + * @param outputFileName Path to the output file name relative to the root of the output archive file + * @param defaultFileInformation Information on default SPDX field data for the files + * @param algorithms algorithms to use to generate checksums + * @param spdxDoc SPDX document which will contain the SPDX file + * @return + * @throws SpdxCollectionException + */ + private SpdxFile convertToSpdxFile( File file, String outputFileName, + SpdxDefaultFileInformation defaultFileInformation, + Set algorithms, + SpdxDocument spdxDoc ) throws SpdxCollectionException + { + String relativePath = convertFilePathToSpdxFileName( outputFileName ); + ArrayList fileTypes = new ArrayList<>(); + fileTypes.add( extensionToFileType( getExtension( file ) ) ); + Set checksums; + try + { + checksums = generateChecksum( file, algorithms ); + } + catch ( SpdxCollectionException | InvalidSPDXAnalysisException e1 ) + { + throw new SpdxCollectionException( "Unable to generate checksum for file "+file.getName() ); + } + AnyLicenseInfo concludedLicense = null; + AnyLicenseInfo license = null; + String licenseComment = defaultFileInformation.getLicenseComment(); + if ( isSourceFile( fileTypes ) && file.length() < SpdxSourceFileParser.MAXIMUM_SOURCE_FILE_LENGTH ) + { + List fileSpdxLicenses = null; + try + { + fileSpdxLicenses = SpdxSourceFileParser.parseFileForSpdxLicenses( file ); + } + catch ( SpdxSourceParserException ex ) + { + LOG.error( "Error parsing for SPDX license ID's", ex ); + } + if ( fileSpdxLicenses != null && fileSpdxLicenses.size() > 0 ) + { + // The file has declared licenses of the form SPDX-License-Identifier: licenseId + try + { + if ( fileSpdxLicenses.size() == 1 ) + { + license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( fileSpdxLicenses.get( 0 ) ); + } + else + { + Set licenseSet = new HashSet<>(); + for ( String licenseExpression : fileSpdxLicenses ) + { + licenseSet.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( licenseExpression ) ); + } + license = spdxDoc.createConjunctiveLicenseSet( licenseSet ); + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file - unable to create a license set", e ); + } + if ( licenseComment == null ) + { + licenseComment = ""; + } + else if ( licenseComment.length() > 0 ) + { + licenseComment = licenseComment.concat( "; " ); + } + licenseComment = licenseComment.concat( "This file contains SPDX-License-Identifiers for " ); + licenseComment = licenseComment.concat( license.toString() ); + } + } + if ( license == null ) + { + try + { + license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getDeclaredLicense() ); + concludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getConcludedLicense() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file - unable create default file license", e ); + } + } + else + { + concludedLicense = license; + } + + String copyright = defaultFileInformation.getCopyright(); + String notice = defaultFileInformation.getNotice(); + String comment = defaultFileInformation.getComment(); + String[] defaultContributors = defaultFileInformation.getContributors(); + List contributors; + if ( defaultContributors != null ) { + contributors = Arrays.asList( defaultFileInformation.getContributors() ); + } else { + contributors = new ArrayList<>(); + } + + SpdxFile retval = null; + //TODO: Add annotation + try + { + List seenLicenses = new ArrayList<>(); + seenLicenses.add( license ); + Checksum sha1 = null; + for ( Checksum checksum:checksums ) + { + if (ChecksumAlgorithm.SHA1.toString().equals( checksum.getAlgorithm() )) { + sha1 = checksum; + break; + } + } + retval = spdxDoc.createSpdxFile( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), + relativePath, concludedLicense, seenLicenses, + copyright, + spdxDoc.createChecksum( ChecksumAlgorithm.SHA1, sha1.getValue() ) ) + .setComment( comment ) + .setLicenseComments( licenseComment ) + .setFileTypes( fileTypes ) + .setFileContributors( contributors ) + .build(); + + + retval.setNoticeText( notice ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file", e ); + } + + return retval; + } + + /** + * @param fileTypes + * @return true if the fileTypes contain a source file type + */ + protected boolean isSourceFile( Collection fileTypes ) + { + for ( FileType ft : fileTypes ) + { + if ( ft == FileType.SOURCE ) + { + return true; + } + } + return false; + } + + /** + * Create the SPDX file name from a system specific path name + * + * @param filePath system specific file path relative to the top of the archive root to the top of the archive + * directory where the file is stored. + * @return + */ + public String convertFilePathToSpdxFileName( String filePath ) + { + String result = filePath.replace( '\\', '/' ); + if ( !result.startsWith( "./" ) ) + { + result = "./" + result; + } + return result; + } + + public String getExtension( File file ) + { + String fileName = file.getName(); + int lastDot = fileName.lastIndexOf( '.' ); + if ( lastDot < 1 ) + { + return ""; + } + else + { + return fileName.substring( lastDot + 1 ); + } + } + + protected static FileType extensionToFileType( String fileExtension ) + { + FileType retval = EXT_TO_FILE_TYPE.get( fileExtension.trim().toUpperCase() ); + if ( retval == null ) + { + retval = FileType.OTHER; + } + return retval; + } + + /** + * @return SPDX Files which have been acquired through the collectFilesInDirectory method + */ + public Collection getFiles() + { + return spdxFiles.values(); + } + + /** + * @return SPDX Snippets collected through the collectFilesInDirectory method + */ + public List getSnippets() + { + return this.spdxSnippets; + } + + /** + * @return all license information used in the SPDX files + */ + public Collection getLicenseInfoFromFiles() + { + return licensesFromFiles; + } + + /** + * Create a verification code from all SPDX files collected + * + * @param spdxFilePath Complete file path for the SPDX file - this will be excluded from the verification code + * @param spdxDoc SPDX document which will contain the package verification code. + * @return package verification code + * @throws NoSuchAlgorithmException on error generating checksum + * @throws InvalidSPDXAnalysisException on SPDX parsing errors + */ + public SpdxPackageVerificationCode getVerificationCode( String spdxFilePath, SpdxDocument spdxDoc ) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException + { + List excludedFileNamesFromVerificationCode = new ArrayList<>(); + + if ( spdxFilePath != null && spdxFiles.containsKey( spdxFilePath ) ) + { + Optional excludedFileName = spdxFiles.get( spdxFilePath ).getName(); + if ( excludedFileName.isPresent() ) + { + excludedFileNamesFromVerificationCode.add( excludedFileName.get() ); + } + } + SpdxPackageVerificationCode verificationCode; + verificationCode = calculatePackageVerificationCode( spdxFiles.values(), + excludedFileNamesFromVerificationCode, spdxDoc ); + return verificationCode; + } + + /** + * Calculate the package verification code for a collection of SPDX files + * + * @param spdxFiles Files used to calculate the verification code + * @param excludedFileNamesFromVerificationCode List of file names to exclude + * @param spdxDoc SPDX document which will contain the Package Verification Code + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidSPDXAnalysisException + */ + private SpdxPackageVerificationCode calculatePackageVerificationCode( Collection spdxFiles, + List excludedFileNamesFromVerificationCode, + SpdxDocument spdxDoc ) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException + { + List fileChecksums = new ArrayList<>(); + for ( SpdxFile file : spdxFiles ) + { + Optional filename = file.getName(); + if ( filename.isPresent() && includeInVerificationCode( file.getName().get(), excludedFileNamesFromVerificationCode ) ) + { + fileChecksums.add( file.getSha1() ); + } + } + Collections.sort( fileChecksums ); + MessageDigest verificationCodeDigest = MessageDigest.getInstance( "SHA-1" ); + for ( String fileChecksum : fileChecksums ) + { + byte[] hashInput = fileChecksum.getBytes( StandardCharsets.UTF_8 ); + verificationCodeDigest.update( hashInput ); + } + String value = convertChecksumToString( verificationCodeDigest.digest() ); + return spdxDoc.createPackageVerificationCode( value, excludedFileNamesFromVerificationCode ); + } + + private boolean includeInVerificationCode( String name, List excludedFileNamesFromVerificationCode ) + { + for ( String s : excludedFileNamesFromVerificationCode ) + { + if ( s.equals( name ) ) + { + return false; + } + } + return true; + } + + /** + * Converts an array of bytes to a string compliant with the SPDX sha1 representation + * + * @param digestBytes + * @return + */ + public static String convertChecksumToString( byte[] digestBytes ) + { + StringBuilder sb = new StringBuilder(); + for ( byte digestByte : digestBytes ) + { + String hex = Integer.toHexString( 0xff & digestByte ); + if ( hex.length() < 2 ) + { + sb.append( '0' ); + } + sb.append( hex ); + } + return sb.toString(); + } + + /** + * Generate the Sha1 for a given file. Must have read access to the file. This method is equivalent to calling + * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. + * + * @param file file to generate checksum for + * @param builder Builder for the SPDX document that will contain the checksum + * @return SHA1 checksum of the input file + * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read + * @throws InvalidSPDXAnalysisException + */ + public static Checksum generateSha1( File file ) throws SpdxCollectionException, InvalidSPDXAnalysisException + { + Set sha1 = new HashSet<>(); + sha1.add( "SHA-1" ); + return generateChecksum( file, sha1 ).iterator().next(); + } + + /** + * Generate checksums for a given file using each algorithm supplied. Must have read access to the file. + * + * @param file file whose checksum is to be generated + * @param algorithms algorithms to generate the checksums + * @return {@code Set} of checksums for file using each algorithm specified + * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read + * @throws InvalidSPDXAnalysisException + */ + public static Set generateChecksum( File file, Set algorithms ) throws SpdxCollectionException, InvalidSPDXAnalysisException + { + Set checksums = new HashSet<>(); + + byte[] buffer; + try + { + buffer = Files.readAllBytes( file.toPath() ); + } + catch ( IOException e ) + { + throw new SpdxCollectionException( "IO error while calculating checksums.", e ); + } + + for ( String algorithm : algorithms ) + { + String checksumAlgorithm = checksumAlgorithms.get( algorithm ); + + MessageDigest digest; + try + { + digest = MessageDigest.getInstance( checksumAlgorithm ); + } + catch ( NoSuchAlgorithmException e ) + { + throw new SpdxCollectionException( e ); + } + + digest.update( buffer ); + String checksum = convertChecksumToString( digest.digest() ); + checksums.add( new Checksum( algorithm, checksum ) ); + } + + return checksums; + } +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java new file mode 100644 index 0000000..b586974 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java @@ -0,0 +1,960 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Contributor; +import org.apache.maven.model.License; +import org.apache.maven.project.DefaultProjectBuildingRequest; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.ProjectBuildingRequest; +import org.apache.maven.project.ProjectBuildingResult; +import org.apache.maven.shared.dependency.graph.DependencyNode; +import org.spdx.core.CoreModelObject; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.core.SpdxInvalidIdException; +import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.conversion.Spdx2to3Converter; +import org.spdx.library.model.v2.Checksum; +import org.spdx.library.model.v2.SpdxPackageVerificationCode; +import org.spdx.library.model.v2.enumerations.Purpose; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; +import org.spdx.library.model.v3_0_1.core.Agent; +import org.spdx.library.model.v3_0_1.core.CreationInfo; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.core.ExternalElement; +import org.spdx.library.model.v3_0_1.core.ExternalMap; +import org.spdx.library.model.v3_0_1.core.Hash; +import org.spdx.library.model.v3_0_1.core.HashAlgorithm; +import org.spdx.library.model.v3_0_1.core.LifecycleScopeType; +import org.spdx.library.model.v3_0_1.core.Relationship; +import org.spdx.library.model.v3_0_1.core.RelationshipCompleteness; +import org.spdx.library.model.v3_0_1.core.RelationshipType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.expandedlicensing.NoAssertionLicense; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.library.model.v3_0_1.simplelicensing.LicenseExpression; +import org.spdx.library.model.v3_0_1.software.Sbom; +import org.spdx.library.model.v3_0_1.software.SoftwarePurpose; +import org.spdx.library.model.v3_0_1.software.SpdxFile; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.maven.OutputFormat; +import org.spdx.storage.ISerializableModelStore; +import org.spdx.storage.IModelStore.IdType; +import org.spdx.storage.simple.InMemSpdxStore; +import org.spdx.v3jsonldstore.JsonLDStore; + +/** + * Adds dependency information into the spdxDoc + * @author Gary O'Neall + * + */ +public class SpdxV3DependencyBuilder + extends AbstractDependencyBuilder +{ + private SpdxDocument spdxDoc; + private SpdxV3LicenseManager licenseManager; + private SpdxV3DocumentBuilder builder; + + /** + * @param builder The document builder + * @param createExternalRefs if true, create external references for dependencies + * @param generatePurls if true, generate a Package URL and include as an external identifier for the dependencies + * @param useArtifactID if true, use the artifact ID for the name of the dependency package, otherwise use the Maven configured project name + * @param includeTransitiveDependencies If true, include transitive dependencies, otherwise include only direct dependencies + */ + public SpdxV3DependencyBuilder( SpdxV3DocumentBuilder builder, boolean createExternalRefs, + boolean generatePurls, boolean useArtifactID, + boolean includeTransitiveDependencies ) + { + super( createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); + this.builder = builder; + this.spdxDoc = builder.getSpdxDoc(); + this.licenseManager = builder.getLicenseManager(); + } + + @Override + protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode dependencyNode, + ProjectBuilder mavenProjectBuilder, + MavenSession session, MavenProject mavenProject ) + throws LicenseMapperException, InvalidSPDXAnalysisException + { + if ( !(parentPackage instanceof SpdxPackage) ) + { + LOG.error( String.format( "Invalid type for parent package. Expected 'SpdxPackage', found %s", + parentPackage.getClass().getName() ) ); + return; + } + Artifact dependency = dependencyNode.getArtifact(); + String scope = dependency.getScope(); + RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); + if ( relType == RelationshipType.OTHER ) + { + LOG.warn( + "Could not determine the SPDX relationship type for dependency artifact ID " + dependency.getArtifactId() + " scope " + scope ); + } + + Element dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, + mavenProject, useArtifactID ); + + spdxDoc.createLifecycleScopedRelationship(spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setRelationshipType( relType ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( (SpdxPackage)parentPackage ) + .addTo( dependencyPackage ) + .setScope( scopeToLifecycleScope( scope ) ) + .setComment( "Relationship created based on Maven POM information" ) + .build(); + LOG.debug( "Added relationship of type " + relType + " for " + dependencyPackage.getName() ); + + if ( includeTransitiveDependencies ) { + addMavenDependencies( mavenProjectBuilder, session, mavenProject, dependencyNode, dependencyPackage ); + } + } + + /** + * Translate the scope to the SPDX relationship type + * + * @param scope Maven Dependency Scope (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope) + * @param optional True if this is an optional dependency + * @return SPDX Relationship type based on the scope + */ + private RelationshipType scopeToRelationshipType( String scope, boolean optional ) + { + if ( scope == null ) + { + return RelationshipType.OTHER; + } + else if ( optional ) + { + return RelationshipType.HAS_OPTIONAL_COMPONENT; + } + else if ( scope.equals( "compile" ) || scope.equals( "runtime" ) ) + { + return RelationshipType.HAS_DYNAMIC_LINK; + } + else if ( scope.equals( "test" ) ) + { + return RelationshipType.DEPENDS_ON; + } + else + { + return RelationshipType.OTHER; + } + } + + private LifecycleScopeType scopeToLifecycleScope( String scope ) { + if ( scope == null ) + { + return LifecycleScopeType.OTHER; + } + else if ( scope.equals( "compile" ) || scope.equals( "runtime" ) ) + { + return LifecycleScopeType.RUNTIME; + } + else if ( scope.equals( "test" ) ) + { + return LifecycleScopeType.TEST; + } + else + { + return LifecycleScopeType.OTHER; + } + } + + /** + * Create an SPDX package from the information in a Maven Project + * + * @param project Maven project + * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used + * @return SPDX Package generated from the metadata in the Maven Project + * @throws IOException On errors reading Maven file information + * @throws SpdxCollectionException On errors with SPDX collections + * @throws NoSuchAlgorithmException if no checksum algorithm was found + * @throws LicenseMapperException on errors mapping or creating SPDX custom licenses + * @throws InvalidSPDXAnalysisException on any other general SPDX errors + */ + private SpdxPackage createSpdxPackage( MavenProject project, boolean useArtifactID ) throws SpdxCollectionException, NoSuchAlgorithmException, LicenseMapperException, InvalidSPDXAnalysisException + { + SpdxDefaultFileInformation fileInfo = new SpdxDefaultFileInformation(); + + // initialize the SPDX information from the project + String packageName = project.getName(); + if ( packageName == null || packageName.isEmpty() || useArtifactID ) + { + packageName = project.getGroupId() + ":" + project.getArtifactId(); + } + List contributors = project.getContributors(); + ArrayList fileContributorList = new ArrayList<>(); + if ( contributors != null ) + { + for ( Contributor contributor : contributors ) + { + fileContributorList.add( contributor.getName() ); + } + } + String copyright = "UNSPECIFIED"; + String notice = "UNSPECIFIED"; + String downloadLocation = "NOASSERTION"; + AnyLicenseInfo declaredLicense = mavenLicensesToSpdxLicense( project.getLicenses() ); + fileInfo.setComment( "" ); + fileInfo.setConcludedLicense( "NOASSERTION" ); + fileInfo.setContributors( fileContributorList.toArray( new String[0] ) ); + fileInfo.setCopyright( copyright ); + fileInfo.setDeclaredLicense( declaredLicense.toString() ); + fileInfo.setLicenseComment( "" ); + fileInfo.setNotice( notice ); + + SpdxPackage retval = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( packageName ) + .setCopyrightText( copyright ) + .setDownloadLocation( downloadLocation ) + .addAllExternalIdentifier( SpdxExternalIdBuilder.getDefaultExternalIdentifiers( spdxDoc, generatePurls, project ) ) + .build(); + if ( generatePurls ) + { + retval.setPackageUrl( SpdxExternalRefBuilder.generatePurl( project ) ); + } + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( retval ) + .addTo( declaredLicense ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .build(); + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( retval ) + .addTo( new NoAssertionLicense() ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .build(); + + if ( project.getVersion() != null ) + { + retval.setPackageVersion( project.getVersion() ); + } + if ( project.getDescription() != null ) + { + retval.setDescription( project.getDescription() ); + retval.setSummary( project.getDescription() ); + } + if ( project.getOrganization() != null ) + { + retval.getOriginatedBys().add( spdxDoc.createOrganization( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( project.getOrganization().getName() ) + .build() ); + } + if ( project.getUrl() != null ) + { + try { + retval.setHomePage( project.getUrl() ); + } catch ( InvalidSPDXAnalysisException e ) { + LOG.warn( "Invalid homepage for dependency " + project.getArtifactId() + ": " + project.getUrl() ); + } + } + return retval; + } + + /** + * Create an SPDX Document using the mavenProjectBuilder to resolve properties + * including inherited properties + * @param artifact Maven dependency artifact + * @param mavenProjectBuilder project builder for the repo containing the POM file + * @param session Maven session for building the project + * @param mavenProject Maven project + * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used + * @return SPDX Package build from the MavenProject metadata + * @throws InvalidSPDXAnalysisException on errors generating SPDX + * @throws LicenseMapperException on errors mapping licenses or creating custom licenses + */ + private Element createSpdxPackage( Artifact artifact, + ProjectBuilder mavenProjectBuilder, MavenSession session, + MavenProject mavenProject, boolean useArtifactID ) throws LicenseMapperException, InvalidSPDXAnalysisException + { + LOG.debug( "Creating SPDX package for artifact " + artifact.getArtifactId() ); + if ( artifact.getFile() == null ) + { + LOG.debug( "Artifact file is null" ); + } + else + { + LOG.debug( "Artifact file name = " + artifact.getFile().getName() ); + } + File spdxFile = null; + if ( artifact.getFile() != null ) + { + spdxFile = artifactFileToSpdxFile( artifact.getFile(), SpdxMajorVersion.VERSION_3 ); + } + Element retval = null; + if ( spdxFile != null && spdxFile.exists() ) + { + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Looking for SPDX file " + spdxFile.getAbsolutePath() ); + try + { + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Dependency information collected from SPDX spec version 3 file " + spdxFile.getAbsolutePath() ); + + SpdxDocument externalSpdxDoc = spdxDocumentFromFile( spdxFile.getPath() ); + if ( createExternalRefs ) + { + retval = createExternalSpdxPackage( externalSpdxDoc, spdxFile, artifact.getGroupId(), + artifact.getArtifactId(), artifact.getVersion() ); + } + else + { + retval = copyPackageInfoFromExternalDoc( externalSpdxDoc, artifact.getGroupId(), + artifact.getArtifactId(), artifact.getVersion() ); + } + } + catch ( IOException e ) + { + LOG.warn( + "IO error reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( SpdxInvalidIdException e ) + { + LOG.warn( + "Invalid SPDX ID exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( InvalidSPDXAnalysisException e ) + { + LOG.warn( + "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( SpdxCollectionException e ) + { + LOG.warn( + "Unable to create file checksum for external SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( Exception e ) + { + LOG.warn( + "Unknown error processing SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + } + if ( retval != null ) + { + return retval; + } + // Check for an SPDX spec version 2 file + spdxFile = artifactFileToSpdxFile( artifact.getFile(), SpdxMajorVersion.VERSION_2 ); + if ( spdxFile != null && spdxFile.exists() ) + { + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Looking for SPDX spec version 2 file " + spdxFile.getAbsolutePath() ); + try + { + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Dependency information collected from SPDX spec version 2 file " + spdxFile.getAbsolutePath() ); + + retval = copyPackageInfoFromV2File( spdxFile.getPath(), artifact.getGroupId(), + artifact.getArtifactId(), artifact.getVersion() ); + } + catch ( IOException e ) + { + LOG.warn( + "IO error reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( SpdxInvalidIdException e ) + { + LOG.warn( + "Invalid SPDX ID exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( InvalidSPDXAnalysisException e ) + { + LOG.warn( + "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + catch ( Exception e ) + { + LOG.warn( + "Unknown error processing SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + } + } + if ( retval != null ) + { + return retval; + } + try + { + ProjectBuildingRequest request = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); + request.setRemoteRepositories( mavenProject.getRemoteArtifactRepositories() ); + for ( ArtifactRepository ar : request.getRemoteRepositories() ) { + LOG.debug( "request Remote repository ID: " + ar.getId() ); + } + for ( ArtifactRepository ar : mavenProject.getRemoteArtifactRepositories() ) { + LOG.debug( "Project Remote repository ID: " + ar.getId() ); + } + ProjectBuildingResult build = mavenProjectBuilder.build( artifact, request ); + MavenProject depProject = build.getProject(); + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Collecting information from project metadata for " + depProject.getArtifactId() ); + retval = createSpdxPackage( depProject, useArtifactID ); + } + catch ( SpdxCollectionException e ) + { + LOG.error( + "SPDX File Collection Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + } + catch ( NoSuchAlgorithmException e ) + { + LOG.error( + "Verification Code Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + } + catch ( ProjectBuildingException e ) + { + LOG.error( + "Maven Project Build Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + } + if ( retval != null ) + { + return retval; + } + LOG.warn( + "Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ". A minimal SPDX package will be created." ); + // Create a minimal SPDX package from dependency + // Name will be the artifact ID + LOG.debug( + "Dependency " + artifact.getArtifactId() + "Using only artifact information to create dependent package" ); + SpdxPackage pkg = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( artifact.getArtifactId() ) + .setComment( "This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file." ) + .setPackageVersion( artifact.getBaseVersion() ) + .addAllExternalIdentifier( SpdxExternalIdBuilder + .getDefaultExternalIdentifiers( spdxDoc, generatePurls, + mavenProject ) ) + .build(); + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( pkg ) + .addTo( new NoAssertionLicense() ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .build(); + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( pkg ) + .addTo( new NoAssertionLicense() ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .build(); + return pkg; + } + + /** + * Creates a copy from an SPDX version 2 file + * @param path + * @param groupId + * @param artifactId + * @param version + * @return + * @throws InvalidSPDXAnalysisException + * @throws IOException + * @throws FileNotFoundException + */ + private Element copyPackageInfoFromV2File( String path, String groupId, String artifactId, String version ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException + { + org.spdx.library.model.v2.SpdxDocument v2Doc = SpdxV2DependencyBuilder.spdxDocumentFromFile( path ); + org.spdx.library.model.v2.SpdxPackage source = SpdxV2DependencyBuilder.findMatchingDescribedPackage( v2Doc, artifactId ); + + Optional downloadLocation = source.getDownloadLocation(); + Optional name = source.getName(); + + SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( name.isPresent() ? name.get() : "NONE" ) + .setCopyrightText( source.getCopyrightText() != null ? source.getCopyrightText() : "NOASSERTION" ) + .setDownloadLocation( downloadLocation.isPresent() ? downloadLocation.get() : "NOASSERTION" ) + .build(); + + Optional pvc = source.getPackageVerificationCode(); + if ( pvc.isPresent() ) + { + dest.getVerifiedUsings().add( dest.createPackageVerificationCode( dest.getModelStore().getNextId( IdType.Anonymous ) ) + .setAlgorithm( HashAlgorithm.SHA1 ) + .setHashValue( pvc.get().getValue() ) + .addAllPackageVerificationCodeExcludedFile( pvc.get().getExcludedFileNames() ) + .build()); + } + + for ( org.spdx.library.model.v2.ExternalRef fromRef : source.getExternalRefs() ) + { + Spdx2to3Converter.addExternalRefToArtifact( fromRef, dest, dest.getModelStore() ); + } + for ( org.spdx.library.model.v2.Annotation fromAnnotation : source.getAnnotations() ) + { + CreationInfo creationInfo = new CreationInfo.CreationInfoBuilder( dest.getModelStore(), + dest.getModelStore().getNextId(IdType.Anonymous), + null) + .setCreated(fromAnnotation.getAnnotationDate()) + .setSpecVersion(SpdxConstantsV3.MODEL_SPEC_VERSION) + .build(); + creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent(fromAnnotation.getAnnotator(), creationInfo) ); + dest.createAnnotation( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setAnnotationType( Spdx2to3Converter.ANNOTATION_TYPE_MAP.get( fromAnnotation.getAnnotationType() ) ) + .setStatement( fromAnnotation.getComment() ) + .setSubject( dest ) + .setCreationInfo( creationInfo ) + .build(); + } + Optional licenseListVersion = v2Doc.getCreationInfo().getLicenseListVersion(); + LicenseExpression declaredLicense = dest.createLicenseExpression( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setLicenseExpression( source.getLicenseDeclared().toString() ) + .build(); + if ( licenseListVersion.isPresent() ) + { + declaredLicense.setLicenseListVersion( licenseListVersion.get() ); + } + dest.createRelationship( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .setFrom( dest ) + .addTo( declaredLicense ) + .build(); + + LicenseExpression concludedLicense = dest.createLicenseExpression( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setLicenseExpression( source.getLicenseConcluded().toString() ) + .build(); + if ( licenseListVersion.isPresent() ) + { + concludedLicense.setLicenseListVersion( licenseListVersion.get() ); + } + dest.createRelationship( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .setFrom( dest ) + .addTo( concludedLicense ) + .build(); + Optional builtDate = source.getBuiltDate(); + + if ( builtDate.isPresent() ) + { + dest.setBuiltTime( builtDate.get() ); + } + Optional comment = source.getComment(); + Optional licenseComments = source.getLicenseComments(); + if ( comment.isPresent() ) + { + if ( licenseComments.isPresent() ) + { + dest.setComment( comment.get() + "; License Comments: " + licenseComments.get() ); + } + else + { + dest.setComment( comment.get() ); + } + + } + else if ( licenseComments.isEmpty() ) + { + dest.setComment( "License Comments: " + licenseComments.get() ); + } + Optional desc = source.getDescription(); + if ( desc.isPresent() ) + { + dest.setDescription( desc.get() ); + } + Optional homePage = source.getHomepage(); + if ( homePage.isPresent() ) + { + dest.setHomePage( homePage.get() ); + } + Optional originator = source.getOriginator(); + if ( originator.isPresent() ) + { + dest.getOriginatedBys().add( Spdx2to3Converter.stringToAgent( originator.get(), dest.getCreationInfo() ) ); + } + Optional pkgFileName = source.getPackageFileName(); + if ( pkgFileName.isPresent() ) + { + SpdxFile packageFile = dest.createSpdxFile( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( pkgFileName.get() ) + .build(); + for ( Checksum fromChecksum : source.getChecksums() ) + { + packageFile.getVerifiedUsings().add( dest.createHash( dest.getModelStore().getNextId( IdType.Anonymous ) ) + .setAlgorithm( Spdx2to3Converter.HASH_ALGORITH_MAP.get( fromChecksum.getAlgorithm() ) ) + .setHashValue( fromChecksum.getValue() ) + .build() ); + } + dest.createRelationship( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( dest ) + .addTo( packageFile ) + .setRelationshipType( RelationshipType.HAS_DISTRIBUTION_ARTIFACT ) + .build(); + } + Optional primaryPurpose = source.getPrimaryPurpose(); + if ( primaryPurpose.isPresent() ) + { + dest.setPrimaryPurpose( Spdx2to3Converter.PURPOSE_MAP.get( primaryPurpose.get() ) ); + } + Optional releaseDate = source.getReleaseDate(); + if ( releaseDate.isPresent() ) + { + dest.setReleaseTime( releaseDate.get() ); + } + Optional sourceInfo = source.getSourceInfo(); + if ( sourceInfo.isPresent() ) + { + dest.setSourceInfo( sourceInfo.get() ); + } + Optional summary = source.getSummary(); + if ( summary.isPresent() ) + { + dest.setSummary( summary.get() ); + } + Optional supplier = source.getSupplier(); + if ( supplier.isPresent() ) { + dest.setSuppliedBy( Spdx2to3Converter.stringToAgent( supplier.get(), dest.getCreationInfo() ) ); + } + Optional validUntil = source.getValidUntilDate(); + if ( validUntil.isPresent() ) + { + dest.setValidUntilTime( validUntil.get() ); + } + Optional versionInfo = source.getVersionInfo(); + if ( versionInfo.isPresent() ) + { + dest.setPackageVersion( versionInfo.get() ); + } + return dest; + } + + /** + * Create and return an external element for the root document or root of an SBOM + * + * @param externalSpdxDoc SPDX Document containing the package to be referenced. + * @param spdxFile SPDX file containing the SPDX document + * @param groupId Group ID for the external artifact + * @param artifactId Artifact ID for the external artifact + * @param version version for the external artifact + * @return package described in the externalSpdxDoc, otherwise null if no package found + * @throws InvalidSPDXAnalysisException on errors creating the external element + * @throws SpdxCollectionException on errors creating the SHA1 has for the file + */ + private @Nullable ExternalElement createExternalSpdxPackage( SpdxDocument externalSpdxDoc, + File spdxFile, + String groupId, + String artifactId, + @Nullable String version ) throws InvalidSPDXAnalysisException, SpdxCollectionException + { + SpdxPackage describedPackage = null; + for ( Element root : externalSpdxDoc.getRootElements() ) + { + if ( root instanceof SpdxPackage ) + { + describedPackage = (SpdxPackage)root; + break; + } + else if ( root instanceof Sbom ) + { + for ( Element sbomRoot : ((Sbom)root).getRootElements() ) + { + if ( sbomRoot instanceof SpdxPackage ) + { + describedPackage = (SpdxPackage)sbomRoot; + break; + } + } + if ( describedPackage != null ) + { + break; + } + } + } + if ( describedPackage == null ) + { + // not found + return null; + } + + ExternalElement retval = new ExternalElement(spdxDoc.getModelStore(), describedPackage.getObjectUri(), + spdxDoc.getCopyManager(), true, describedPackage.getIdPrefix()); + for ( ExternalMap ext : spdxDoc.getSpdxImports() ) + { + if ( describedPackage.getObjectUri().equals( ext.getExternalSpdxId() ) ) + { + return retval; // No need to create the external map + } + } + Hash hash = (Hash)SpdxFileCollector.generateSha1( spdxFile, builder ); + StringBuilder sb = new StringBuilder( groupId ).append( artifactId ); + if ( Objects.nonNull( version )) { + sb.append( version ); + } + String fullArtifactId = sb.toString(); + SpdxFile fileArtifact = spdxDoc.createSpdxFile( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( spdxFile.getName() ) + .setDescription( String.format( "SPDX File for %s", fullArtifactId ) ) + .addVerifiedUsing( hash ) + .build(); + spdxDoc.getSpdxImports().add( spdxDoc.createExternalMap( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .addVerifiedUsing( hash ) + .setExternalSpdxId( describedPackage.getObjectUri() ) + .setDefiningArtifact( fileArtifact ) + .build() ); + return retval; + } + + + /** + * Creates an SPDX document from a file + * @param path Path to the SPDX file + * @return an SPDX Spec version 2 document + * @throws IOException on IO Error + * @throws FileNotFoundException if the file does not exist + * @throws InvalidSPDXAnalysisException on invalid SPDX file + */ + private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException + { + ISerializableModelStore modelStore; + OutputFormat of = OutputFormat.getOutputFormat( null, new File( path ) ); + if (!SpdxMajorVersion.VERSION_3.equals( of.getSpecVersion() )) { + throw new InvalidSPDXAnalysisException( String.format( "Unsupported file type for SPDX Version 2 SPDX documents: %s", of.getSpecVersion().toString() )); + } + modelStore = new JsonLDStore( new InMemSpdxStore() ); + + try ( InputStream inputStream = new FileInputStream( path ) ) + { + CoreModelObject root = modelStore.deSerialize( inputStream, false ); + if ( root instanceof SpdxDocument ) + { + root.setCopyManager( spdxDoc.getCopyManager() ); + return (SpdxDocument)root; + } + else + { + throw new InvalidSPDXAnalysisException( String.format( "Could not find an SPDX document for SPDX file name %s", + path ) ); + } + } + finally + { + if ( modelStore != null ) { + try + { + modelStore.close(); + } + catch ( Exception e ) + { + LOG.error( "Error closing SPDX model store", e ); + } + } + } + } + + /** + * Copies the closest matching described package in the externalSpdxDoc to the returned element + * @param externalSpdxDoc SPDX document containing the described package + * @param groupId Group ID of the artifact + * @param artifactId Artifact ID to search for + * @param version Version of the artifact + * @return SPDX Package with values copied from the externalSpdxDoc + * @throws InvalidSPDXAnalysisException on errors copying from the external document + */ + private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc, String groupId, + String artifactId, String version ) throws InvalidSPDXAnalysisException + { + SpdxPackage source = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); + Optional downloadLocation = source.getDownloadLocation(); + Optional name = source.getName(); + SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( name.isPresent() ? name.get() : "NONE" ) + .setCopyrightText( source.getCopyrightText().orElse( "NOASSERTION" ) ) + .addAllVerifiedUsing( source.getVerifiedUsings() ) + .setDownloadLocation( downloadLocation.isPresent() ? downloadLocation.get() : "NOASSERTION" ) + .addAllExternalIdentifier( source.getExternalIdentifiers() ) + .addAllExternalRef( source.getExternalRefs() ) + .addAllOriginatedBy( source.getOriginatedBys() ) + .build(); + @SuppressWarnings( "unchecked" ) + List sourceRelationships = + (List) SpdxModelFactory.getSpdxObjects( externalSpdxDoc.getModelStore(), externalSpdxDoc.getCopyManager(), + SpdxConstantsV3.CORE_RELATIONSHIP, null, null ) + .filter( spdxObj -> { + try + { + return source.equals( ((Relationship)spdxObj).getFrom() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + LOG.error( String.format( "Error copying relationships from SPDX file for artifact %s", artifactId ), e ); + return false; + } + } ) + .collect( Collectors.toList() ); + for ( Relationship rel : sourceRelationships ) + { + dest.createRelationship( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( dest ) + .setCompleteness( rel.getCompleteness().orElse( RelationshipCompleteness.NO_ASSERTION ) ) + .setRelationshipType( rel.getRelationshipType() ) + .addAllTo( rel.getTos() ) // NOTE: The dest my have the same CopyManager as the relationships for this to copy correctly + .build(); + } + // We don't want to copy any of the properties which have other elements since it + // may duplicate artifacts already included in the document - so we can't use copyFrom + + Optional builtTime = source.getBuiltTime(); + if ( builtTime.isPresent() ) + { + dest.setBuiltTime( builtTime.get() ); + } + Optional comment = source.getComment(); + if ( comment.isPresent() ) + { + dest.setComment( comment.get() ); + } + Optional desc = source.getDescription(); + if ( desc.isPresent() ) + { + dest.setDescription( desc.get() ); + } + Optional homePage = source.getHomePage(); + if ( homePage.isPresent() ) + { + dest.setHomePage( homePage.get() ); + } + Optional primaryPurpose = source.getPrimaryPurpose(); + if ( primaryPurpose.isPresent() ) + { + dest.setPrimaryPurpose( primaryPurpose.get() ); + } + Optional releaseTime = source.getReleaseTime(); + if ( releaseTime.isPresent() ) + { + dest.setReleaseTime( releaseTime.get() ); + } + Optional sourceInfo = source.getSourceInfo(); + if ( sourceInfo.isPresent() ) + { + dest.setSourceInfo( sourceInfo.get() ); + } + Optional summary = source.getSummary(); + if ( summary.isPresent() ) + { + dest.setSummary( summary.get() ); + } + Optional supplier = source.getSuppliedBy(); + if ( supplier.isPresent() ) { + dest.setSuppliedBy( supplier.get() ); + } + Optional validUntil = source.getValidUntilTime(); + if ( validUntil.isPresent() ) + { + dest.setValidUntilTime( validUntil.get() ); + } + Optional versionInfo = source.getPackageVersion(); + if ( versionInfo.isPresent() ) + { + dest.setPackageVersion( versionInfo.get() ); + } + return dest; + } + + /** + * Searched the SPDX document for the closest matching package to the artifactId + * @param externalSpdxDoc Doc containing the package + * @param artifactId Maven artifact ID + * @return the closest matching package described by the doc + * @throws InvalidSPDXAnalysisException on SPDX errors + */ + private SpdxPackage findMatchingDescribedPackage( SpdxDocument externalSpdxDoc, String artifactId ) throws InvalidSPDXAnalysisException + { + Sbom firstFoundSbom = null; + SpdxPackage firstFoundPackage = null; + for ( Element root : externalSpdxDoc.getRootElements() ) + { + if ( root instanceof SpdxPackage ) + { + if ( root.getName().isPresent() && root.getName().get().equals( artifactId ) ) + { + return (SpdxPackage)root; + } else if ( firstFoundPackage == null ) + { + firstFoundPackage =(SpdxPackage)root; + } + } + else if ( root instanceof Sbom ) + { + for ( Element sRoot : ((Sbom)root).getRootElements() ) + { + if ( sRoot instanceof SpdxPackage ) + { + if ( sRoot.getName().isPresent() && sRoot.getName().get().equals( artifactId ) ) + { + return (SpdxPackage)sRoot; + } + } + } + if ( firstFoundSbom == null ) + { + firstFoundSbom = (Sbom)root; + } + } + } + + // If we got here, we didn't find the package in the SPDX document root or the SBOMs at the root of the SPDX document + if ( firstFoundPackage != null ) + { + LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in SPDX file." ); + return firstFoundPackage; + } + if ( firstFoundSbom != null ) + { + for ( Element sRoot : firstFoundSbom.getRootElements() ) + { + if ( sRoot instanceof SpdxPackage ) + { + LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in Sbom." ); + return (SpdxPackage)sRoot; + } + } + } + throw new InvalidSPDXAnalysisException( "SPDX document does not contain any described items." ); + } + + /** + * Convert a list of Maven licenses to an SPDX License + * + * @param mavenLicenses List of maven licenses to map + * @return + * @throws LicenseMapperException + * @throws InvalidSPDXAnalysisException + * @throws LicenseManagerException + */ + private AnyLicenseInfo mavenLicensesToSpdxLicense( List mavenLicenses ) throws LicenseMapperException, InvalidSPDXAnalysisException + { + try + { + // The call below will map non-standard licenses as well as standard licenses + // but will throw an exception if no mapping is found - we'll try this first + // and if there is an error, try just the standard license mapper which will + // return an UNSPECIFIED license type if there is no mapping + return this.licenseManager.mavenLicenseListToSpdxLicense( mavenLicenses ); + } + catch ( LicenseManagerException ex ) + { + return MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( mavenLicenses, spdxDoc ); + } + + } +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java deleted file mode 100644 index 316b9af..0000000 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyInformation.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2024 Source Auditor Inc. - */ -package org.spdx.maven.utils; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.shared.dependency.graph.DependencyNode; - -/** - * @author gary - * - */ -public class SpdxV3DependencyInformation - extends AbstractDependencyInformation -{ - - /** - * @param builder - * @param createExternalRefs - * @param generatePurls - * @param useArtifactID - * @param includeTransitiveDependencies - */ - public SpdxV3DependencyInformation( SpdxV3DocumentBuilder builder, boolean createExternalRefs, - boolean generatePurls, boolean useArtifactID, - boolean includeTransitiveDependencies ) - { - // TODO Auto-generated constructor stub - } - - @Override - public void addMavenDependencies( ProjectBuilder mavenProjectBuilder, MavenSession session, - MavenProject mavenProject, DependencyNode parentNode, Object projectPackage ) - { - // TODO Auto-generated method stub - - } - -} diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index e272acd..8f7e39d 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -5,6 +5,9 @@ package org.spdx.maven.utils; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.List; @@ -89,11 +92,12 @@ public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, licenseManager = new SpdxV3LicenseManager( spdxDoc, useStdLicenseSourceUrls ); } - @Override - public CoreModelObject getSpdxDoc() + /** + * @return the SPDX Document + */ + public SpdxDocument getSpdxDoc() { - // TODO Auto-generated method stub - return null; + return this.spdxDoc; } @Override @@ -104,7 +108,7 @@ public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformati } @Override - public void collectSpdxFileInformation( List sources, String absolutePath, + public void collectSpdxFileInformation( List sources, String baseDir, SpdxDefaultFileInformation defaultFileInformation, HashMap pathSpecificInformation, Set checksumAlgorithms ) @@ -114,45 +118,78 @@ public void collectSpdxFileInformation( List sources, String absolutePa } @Override - public void addDependencyInformation( AbstractDependencyInformation dependencyInformation ) + public void saveSpdxDocumentToFile() throws SpdxBuilderException { - // TODO Auto-generated method stub - + try ( FileOutputStream spdxOut = new FileOutputStream( spdxFile ) ) + { + modelStore.serialize( spdxOut ); + } + catch ( FileNotFoundException e ) + { + throw new SpdxBuilderException( "Error saving SPDX data to file", e ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error collecting SPDX file data", e ); + } + catch ( IOException e ) + { + throw new SpdxBuilderException( "I/O Error saving SPDX data to file", e ); + } } @Override - public void saveSpdxDocumentToFile() + public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException { - // TODO Auto-generated method stub - + if ( nonStandardLicenses != null ) + { + for ( NonStandardLicense nonStandardLicense : nonStandardLicenses ) + { + try + { + // the following will add the non-standard license to the document container + licenseManager.addExtractedLicense( nonStandardLicense ); + } + catch ( LicenseManagerException e ) + { + throw new SpdxBuilderException( "Error adding non standard license", e ); + } + } + } } @Override - public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) + public CoreModelObject getProjectPackage() { // TODO Auto-generated method stub - + return null; } - @Override - public Object getProjectPackage() + public CoreModelObject convertChecksum( String algorithm, String checksum ) { // TODO Auto-generated method stub return null; } @Override - public Object createChecksum( String algorithm, String checksum ) + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) { // TODO Auto-generated method stub return null; } + /** + * @return the licenseManager + */ + public SpdxV3LicenseManager getLicenseManager() + { + return licenseManager; + } + @Override - public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + public List verify() { - // TODO Auto-generated method stub - return null; + return spdxDoc.verify(); } } diff --git a/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java b/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java index 58952ba..c1f069b 100644 --- a/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java +++ b/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java @@ -86,7 +86,7 @@ public void testGetMap() throws LicenseMapperException public void testMavenLicenseListToSpdxLicenseNone() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( + AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList.subList( 0, 0 ), spdxDoc ); assertEquals( new SpdxNoAssertionLicense(), result ); } @@ -98,7 +98,7 @@ public void testMavenLicenseListToSpdxLicenseUnknown() throws LicenseMapperExcep License license = new License(); license.setUrl( "http://not.a.known.url" ); licenseList.add( license ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( + AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); assertEquals( new SpdxNoAssertionLicense(), result ); } @@ -110,7 +110,7 @@ public void testMavenLicenseListToSpdxLicenseSingle() throws LicenseMapperExcept License license = new License(); license.setUrl( APACHE2_URL ); licenseList.add( license ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( + AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); assertEquals( expected, result ); @@ -126,7 +126,7 @@ public void testMavenLicenseListToSpdxLicenseConjunctive() throws LicenseMapperE License licenseM = new License(); licenseM.setUrl( MIT_URL ); licenseList.add( licenseM ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( + AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID + " AND " + MIT_SPDX_ID ); assertEquals( expected, result ); @@ -142,7 +142,7 @@ public void testMavenLicenseListToSpdxLicenseConunctiveUnknown() throws LicenseM License licenseM = new License(); licenseM.setUrl( "http://unknown.url" ); licenseList.add( licenseM ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxLicense( + AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); assertEquals( expected, result ); From 6732710eb79886e3dc2b04d04b95a2a8c7ccb127 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 9 Nov 2024 17:13:14 -0800 Subject: [PATCH 03/10] Intermediate checkin - main code compiles --- .../java/org/spdx/maven/CreateSpdxMojo.java | 15 +- src/main/java/org/spdx/maven/SnippetInfo.java | 21 +- .../maven/utils/AbstractDocumentBuilder.java | 3 +- .../maven/utils/AbstractFileCollector.java | 247 +++++++ .../spdx/maven/utils/SpdxDocumentBuilder.java | 533 -------------- .../spdx/maven/utils/SpdxFileCollector.java | 676 ------------------ .../maven/utils/SpdxProjectInformation.java | 28 - .../maven/utils/SpdxV2DependencyBuilder.java | 7 +- .../maven/utils/SpdxV2DocumentBuilder.java | 8 +- .../spdx/maven/utils/SpdxV2FileCollector.java | 235 +----- .../maven/utils/SpdxV3DependencyBuilder.java | 20 +- .../maven/utils/SpdxV3DocumentBuilder.java | 401 ++++++++++- .../spdx/maven/utils/SpdxV3FileCollector.java | 500 +++++++++++++ 13 files changed, 1180 insertions(+), 1514 deletions(-) create mode 100644 src/main/java/org/spdx/maven/utils/AbstractFileCollector.java delete mode 100644 src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java delete mode 100644 src/main/java/org/spdx/maven/utils/SpdxFileCollector.java create mode 100644 src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index 185f489..02ffab1 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -45,7 +45,8 @@ import org.spdx.maven.utils.SpdxDefaultFileInformation; import org.spdx.maven.utils.AbstractDependencyBuilder; import org.spdx.maven.utils.AbstractDocumentBuilder; -import org.spdx.maven.utils.SpdxFileCollector; +import org.spdx.maven.utils.AbstractFileCollector; +import org.spdx.maven.utils.LicenseManagerException; import org.spdx.maven.utils.SpdxProjectInformation; import org.spdx.maven.utils.SpdxV2DependencyBuilder; import org.spdx.maven.utils.SpdxV2DocumentBuilder; @@ -830,7 +831,15 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen if ( this.licenseDeclared == null ) { List mavenLicenses = mavenProject.getLicenses(); - declaredLicense = builder.mavenLicenseListToSpdxLicenseExpression( mavenLicenses ); + try + { + declaredLicense = builder.mavenLicenseListToSpdxLicenseExpression( mavenLicenses ); + } + catch ( LicenseManagerException e ) + { + getLog().warn( "Unable to map maven licenses to a declared license. Using NOASSERTION" ); + declaredLicense = "NOASSERTION"; + } } else { @@ -901,7 +910,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen { getLog().debug( "Generating checksum for file "+packageFile.getAbsolutePath() ); Set algorithms = getChecksumAlgorithms(); - checksums = SpdxFileCollector.generateChecksum( packageFile, algorithms, builder ); + checksums = AbstractFileCollector.generateChecksum( packageFile, algorithms ); } catch ( SpdxCollectionException | InvalidSPDXAnalysisException e ) { diff --git a/src/main/java/org/spdx/maven/SnippetInfo.java b/src/main/java/org/spdx/maven/SnippetInfo.java index 9fc9619..a0620a1 100644 --- a/src/main/java/org/spdx/maven/SnippetInfo.java +++ b/src/main/java/org/spdx/maven/SnippetInfo.java @@ -15,17 +15,9 @@ */ package org.spdx.maven; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.spdx.core.DefaultStoreNotInitialized; -import org.spdx.library.LicenseInfoFactory; -import org.spdx.library.model.v2.SpdxDocument; -import org.spdx.library.model.v2.license.AnyLicenseInfo; -import org.spdx.library.model.v2.license.InvalidLicenseStringException; import org.spdx.maven.utils.SpdxBuilderException; import org.slf4j.Logger; @@ -98,18 +90,9 @@ public String getComment() return this.comment; } - public AnyLicenseInfo getLicenseConcluded( SpdxDocument spdxDoc ) throws InvalidLicenseStringException, DefaultStoreNotInitialized + public String getLicenseConcluded() { - return LicenseInfoFactory.parseSPDXLicenseStringCompatV2( this.concludedLicense, spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); - } - - public Collection getLicenseInfoInSnippet( SpdxDocument spdxDoc ) throws InvalidLicenseStringException, DefaultStoreNotInitialized - { - List retval = new ArrayList<>(); - retval.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( this.licenseInfoInSnippet, spdxDoc.getModelStore(), - spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() )); - return retval; + return this.concludedLicense; } public String getCopyrightText() diff --git a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java index 9d7535d..bb066d3 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java @@ -132,8 +132,9 @@ public abstract void collectSpdxFileInformation( List sources, String b /** * @param mavenLicenses list of licenses * @return license expression representing the list of mavenLicenses + * @throws LicenseManagerException On error converting license */ - public abstract String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ); + public abstract String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) throws LicenseManagerException; /** * Verifies the top level document diff --git a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java new file mode 100644 index 0000000..725f3e7 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java @@ -0,0 +1,247 @@ +/** + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Source Auditor Inc. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Map.Entry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.FileType; +import org.spdx.maven.Checksum; + +/** + * Collects SPDX file information from directories. + * + * Concrete subclasses implement specific SPDX spec specific formats + * + * @author Gary O'Neall + */ +public abstract class AbstractFileCollector +{ + protected static final Logger LOG = LoggerFactory.getLogger( AbstractFileCollector.class ); + + // constants for mapping extensions to types. + static final String SPDX_FILE_TYPE_CONSTANTS_PROP_PATH = "resources/SpdxFileTypeConstants.prop"; + + public static final Map EXT_TO_FILE_TYPE = new HashMap<>(); + + static + { + loadFileExtensionConstants(); + } + + public static final Map CHECKSUM_ALGORITHMS = new HashMap<>(); + + static + { + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.SHA1.toString(), "SHA-1" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.SHA224.toString(), "SHA-224" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.SHA256.toString(), "SHA-256" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.SHA384.toString(), "SHA-384" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.SHA3_384.toString(), "SHA-512" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.MD2.toString(), "MD2" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.MD4.toString(), "MD4" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.MD5.toString(), "MD5" ); + CHECKSUM_ALGORITHMS.put( ChecksumAlgorithm.MD6.toString(), "MD6" ); + } + + /** + * Load file type constants from the properties file + */ + private static void loadFileExtensionConstants() + { + Properties prop = new Properties(); + try ( InputStream is = SpdxV2FileCollector.class.getClassLoader().getResourceAsStream( + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ) ) + { + if ( is == null ) + { + LOG.error( "Unable to load properties file " + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ); + return; + } + prop.load( is ); + Iterator> iter = prop.entrySet().iterator(); + while ( iter.hasNext() ) + { + Entry entry = iter.next(); + String fileTypeStr = (String)entry.getKey(); + FileType fileType = FileType.valueOf( fileTypeStr ); + String[] extensions = ((String)entry.getValue()).split( "," ); + for ( String extension:extensions ) + { + try + { + String trimmedExtension = extension.toUpperCase().trim(); + if ( EXT_TO_FILE_TYPE.containsKey( trimmedExtension ) ) + { + LOG.warn( "Duplicate file extension: "+trimmedExtension ); + } + EXT_TO_FILE_TYPE.put( trimmedExtension, fileType ); + } + catch ( Exception ex ) { + LOG.error( "Error adding file extensions to filetype map", ex ); + } + } + } + } + catch ( IOException e ) + { + LOG.warn( + "WARNING: Error reading SpdxFileTypeConstants properties file. All file types will be mapped to Other." ); + } + } + + public String getExtension( File file ) + { + String fileName = file.getName(); + int lastDot = fileName.lastIndexOf( '.' ); + if ( lastDot < 1 ) + { + return ""; + } + else + { + return fileName.substring( lastDot + 1 ); + } + } + + /** + * @param fileTypes + * @return true if the fileTypes contain a source file type + */ + protected boolean isSourceFile( Collection fileTypes ) + { + for ( FileType ft : fileTypes ) + { + if ( ft == FileType.SOURCE ) + { + return true; + } + } + return false; + } + + /** + * Create the SPDX file name from a system specific path name + * + * @param filePath system specific file path relative to the top of the archive root to the top of the archive + * directory where the file is stored. + * @return + */ + public String convertFilePathToSpdxFileName( String filePath ) + { + String result = filePath.replace( '\\', '/' ); + if ( !result.startsWith( "./" ) ) + { + result = "./" + result; + } + return result; + } + + protected FileType extensionToFileType( String fileExtension ) + { + return EXT_TO_FILE_TYPE.getOrDefault( fileExtension.trim().toUpperCase(), FileType.OTHER ); + + } + + /** + * Converts an array of bytes to a string compliant with the SPDX sha1 representation + * + * @param digestBytes + * @return + */ + public static String convertChecksumToString( byte[] digestBytes ) + { + StringBuilder sb = new StringBuilder(); + for ( byte digestByte : digestBytes ) + { + String hex = Integer.toHexString( 0xff & digestByte ); + if ( hex.length() < 2 ) + { + sb.append( '0' ); + } + sb.append( hex ); + } + return sb.toString(); + } + + /** + * Generate the Sha1 for a given file. Must have read access to the file. This method is equivalent to calling + * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. + * + * @param file file to generate checksum for + * @param builder Builder for the SPDX document that will contain the checksum + * @return SHA1 checksum of the input file + * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read + * @throws InvalidSPDXAnalysisException + */ + public static Checksum generateSha1( File file ) throws SpdxCollectionException, InvalidSPDXAnalysisException + { + Set sha1 = new HashSet<>(); + sha1.add( "SHA-1" ); + return generateChecksum( file, sha1 ).iterator().next(); + } + + /** + * Generate checksums for a given file using each algorithm supplied. Must have read access to the file. + * + * @param file file whose checksum is to be generated + * @param algorithms algorithms to generate the checksums + * @return {@code Set} of checksums for file using each algorithm specified + * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read + * @throws InvalidSPDXAnalysisException + */ + public static Set generateChecksum( File file, Set algorithms ) throws SpdxCollectionException, InvalidSPDXAnalysisException + { + Set checksums = new HashSet<>(); + + byte[] buffer; + try + { + buffer = Files.readAllBytes( file.toPath() ); + } + catch ( IOException e ) + { + throw new SpdxCollectionException( "IO error while calculating checksums.", e ); + } + + for ( String algorithm : algorithms ) + { + String checksumAlgorithm = CHECKSUM_ALGORITHMS.get( algorithm ); + + MessageDigest digest; + try + { + digest = MessageDigest.getInstance( checksumAlgorithm ); + } + catch ( NoSuchAlgorithmException e ) + { + throw new SpdxCollectionException( e ); + } + + digest.update( buffer ); + String checksum = convertChecksumToString( digest.digest() ); + checksums.add( new Checksum( algorithm, checksum ) ); + } + + return checksums; + } + +} diff --git a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java deleted file mode 100644 index 2bfeffa..0000000 --- a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright 2014 Source Auditor Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.spdx.maven.utils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URI; -import java.security.NoSuchAlgorithmException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.model.fileset.FileSet; - -import org.spdx.jacksonstore.MultiFormatStore; -import org.spdx.jacksonstore.MultiFormatStore.Format; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.ModelCopyManager; -import org.spdx.library.SpdxConstants; -import org.spdx.library.SpdxVerificationHelper; -import org.spdx.library.model.Annotation; -import org.spdx.library.model.Relationship; -import org.spdx.library.model.SpdxCreatorInformation; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxElement; -import org.spdx.library.model.SpdxModelFactory; -import org.spdx.library.model.SpdxPackage; -import org.spdx.library.model.SpdxPackageVerificationCode; -import org.spdx.library.model.enumerations.ChecksumAlgorithm; -import org.spdx.library.model.enumerations.RelationshipType; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.ListedLicenses; -import org.spdx.library.model.license.SpdxListedLicense; -import org.spdx.maven.ExternalReference; -import org.spdx.maven.NonStandardLicense; -import org.spdx.maven.OutputFormat; -import org.spdx.spdxRdfStore.RdfStore; -import org.spdx.storage.IModelStore.IdType; -import org.spdx.storage.ISerializableModelStore; -import org.spdx.storage.simple.InMemSpdxStore; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Builds SPDX documents for a given set of source files. This is the primary class to use when creating SPDX documents - * based on project files. - * - * @author Gary O'Neall - */ -public class SpdxDocumentBuilder -{ - private static final Logger LOG = LoggerFactory.getLogger( SpdxDocumentBuilder.class ); - - private static final String UNSPECIFIED = "UNSPECIFIED"; - - public static final String NULL_SHA1 = "cf23df2207d99a74fbe169e3eba035e633b65d94"; - - //TODO: Use a previous SPDX to document file specific information and update - //TODO: Map the SPDX document to the Maven build artifacts - DateFormat format = new SimpleDateFormat( SpdxConstants.SPDX_DATE_FORMAT ); - - private MavenProject project; - private boolean generatePurls; - private SpdxDocument spdxDoc; - private SpdxPackage projectPackage; - private SpdxV2LicenseManager licenseManager; - private File spdxFile; - - private ISerializableModelStore modelStore; - - private ModelCopyManager copyManager; - - /** - * @param spdxFile File to store the SPDX document results - * @param spdxDocumentNamespace URI for SPDX document - must be unique - * @param useStdLicenseSourceUrls if true, map any SPDX standard license source URL to license ID. Note: - * significant performance degradation - * @param outputFormat File format for the SPDX file - * @throws SpdxBuilderException - * @throws LicenseMapperException - */ - public SpdxDocumentBuilder( MavenProject project, boolean generatePurls, File spdxFile, URI spdxDocumentNamespace, - boolean useStdLicenseSourceUrls, OutputFormat outputFormat ) throws SpdxBuilderException, LicenseMapperException - { - this.project = project; - this.generatePurls = generatePurls; - this.spdxFile = spdxFile; - - if ( spdxDocumentNamespace == null ) - { - throw new SpdxBuilderException( "Missing spdxDocumentNamespace" ); - } - - // Handle the SPDX file - if ( !spdxFile.exists() ) - { - File parentDir = spdxFile.getParentFile(); - if ( parentDir != null && !parentDir.exists() ) - { - if ( !parentDir.mkdirs() ) - { - throw new SpdxBuilderException( "Unable to create directories for SPDX file" ); - } - } - - try - { - if ( !spdxFile.createNewFile() ) - { - throw new SpdxBuilderException( "Unable to create the SPDX file" ); - } - } - catch ( IOException e ) - { - throw new SpdxBuilderException( "IO error creating the SPDX file", e ); - } - } - if ( !spdxFile.canWrite() ) - { - throw new SpdxBuilderException( "Unable to write to SPDX file - check permissions: " + spdxFile.getPath() ); - } - - // create the SPDX document - try - { - modelStore = outputFormat == OutputFormat.RDF_XML ? new RdfStore() : new MultiFormatStore( new InMemSpdxStore(), Format.JSON_PRETTY ); - copyManager = new ModelCopyManager(); - spdxDoc = SpdxModelFactory.createSpdxDocument( modelStore, spdxDocumentNamespace.toString(), copyManager ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error creating SPDX document", e ); - } - - // process the licenses - licenseManager = new SpdxV2LicenseManager( spdxDoc, useStdLicenseSourceUrls ); - } - - /** - * Add non-standard licenses to the SPDX document. - * - * @param nonStandardLicenses - * @throws SpdxBuilderException - */ - public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException - { - if ( nonStandardLicenses != null ) - { - for ( NonStandardLicense nonStandardLicense : nonStandardLicenses ) - { - try - { - // the following will add the non-standard license to the document container - licenseManager.addExtractedLicense( nonStandardLicense ); - } - catch ( LicenseManagerException e ) - { - throw new SpdxBuilderException( "Error adding non standard license", e ); - } - } - } - } - - public SpdxDocument getSpdxDoc() - { - return this.spdxDoc; - } - - public void saveSpdxDocumentToFile() throws SpdxBuilderException - { - try ( FileOutputStream spdxOut = new FileOutputStream( spdxFile ) ) - { - modelStore.serialize( spdxDoc.getDocumentUri(), spdxOut ); - } - catch ( FileNotFoundException e ) - { - throw new SpdxBuilderException( "Error saving SPDX data to file", e ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error collecting SPDX file data", e ); - } - catch ( IOException e ) - { - throw new SpdxBuilderException( "I/O Error saving SPDX data to file", e ); - } - } - - /** - * Add dependency information to the SPDX file - * - * @param dependencyInformation dependency information collected from the project POM file - * @throws SpdxBuilderException - */ - public void addDependencyInformation( SpdxDependencyInformation dependencyInformation ) throws SpdxBuilderException - { - Map> packageRelationships = dependencyInformation.getRelationships(); - if ( packageRelationships != null ) - { - for ( Map.Entry> entry : packageRelationships.entrySet() ) - { - SpdxElement parentElement = entry.getKey(); - List relationships = entry.getValue(); - - for ( Relationship relationship : relationships ) - { - try - { - parentElement.addRelationship( relationship ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException("Unable to set package dependencies", e); - } - } - } - } - } - - /** - * Fill in the document level information for SPDX - * - * @param projectInformation project information to be used - * @throws SpdxBuilderException - */ - public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) throws SpdxBuilderException - { - try - { - // document comment - if ( projectInformation.getDocumentComment() != null && !projectInformation.getDocumentComment().isEmpty() ) - { - spdxDoc.setComment( projectInformation.getDocumentComment() ); - } - // creator - fillCreatorInfo( projectInformation ); - // data license - SpdxListedLicense dataLicense = LicenseInfoFactory.getListedLicenseById( SpdxConstants.SPDX_DATA_LICENSE_ID ); - spdxDoc.setDataLicense( dataLicense ); - // annotations - if ( projectInformation.getDocumentAnnotations() != null && projectInformation.getDocumentAnnotations().length > 0 ) - { - spdxDoc.setAnnotations( toSpdxAnnotations( projectInformation.getDocumentAnnotations() ) ); - } - //TODO: Implement document annotations - //TODO: Add document level relationships - spdxDoc.setName( projectInformation.getName() ); // Same as package name - // Package level information - projectPackage = createSpdxPackage( projectInformation ); - Relationship documentContainsRelationship = spdxDoc.createRelationship( projectPackage, RelationshipType.DESCRIBES, "" ); - spdxDoc.addRelationship( documentContainsRelationship ); - } - catch ( InvalidSPDXAnalysisException | MojoExecutionException e ) - { - throw new SpdxBuilderException( "Error adding package information to SPDX document", e ); - } - } - - private Collection toSpdxAnnotations( org.spdx.maven.Annotation[] annotations ) throws MojoExecutionException - { - List retval = new ArrayList<>(); - for ( org.spdx.maven.Annotation annotation: annotations ) - { - retval.add( annotation.toSpdxAnnotation( spdxDoc ) ); - } - return retval; - } - - private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation ) throws SpdxBuilderException - { - //TODO: Add annotations - //TODO: Add relationships - //TODO: Add comment - String copyrightText = projectInformation.getCopyrightText(); - if ( copyrightText == null ) - { - copyrightText = UNSPECIFIED; - } - String downloadUrl = null; - - if ( SpdxVerificationHelper.isValidUri( projectInformation.getDownloadUrl() )) - { - downloadUrl = projectInformation.getDownloadUrl(); - } - else - { - LOG.warn( "Invalid download location in POM file: " + projectInformation.getDownloadUrl() ); - } - if ( downloadUrl == null ) - { - downloadUrl = UNSPECIFIED; - } - SpdxPackageVerificationCode nullPackageVerificationCode; - try - { - nullPackageVerificationCode = spdxDoc.createPackageVerificationCode( NULL_SHA1, new ArrayList() ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error creating null package verification code", e ); - } - SpdxPackage pkg; - try - { - pkg = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri() ), - projectInformation.getName(), projectInformation.getConcludedLicense(), - copyrightText, projectInformation.getDeclaredLicense() ) - .setDownloadLocation( downloadUrl ) - .setPackageVerificationCode( nullPackageVerificationCode ) - .setPrimaryPurpose( projectInformation.getPrimaryPurpose() ) - .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) - .build(); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error creating initial package", e ); - } - // Annotations - if ( projectInformation.getPackageAnnotations() != null && projectInformation.getPackageAnnotations().length > 0 ) - { - try - { - pkg.setAnnotations( toSpdxAnnotations( projectInformation.getPackageAnnotations() ) ); - } - catch ( InvalidSPDXAnalysisException | MojoExecutionException e ) - { - throw new SpdxBuilderException( "Error adding package annotations to SPDX document", e ); - } - } - try - { - // description - if ( projectInformation.getDescription() != null ) - { - pkg.setDescription( projectInformation.getDescription() ); - } - // download url - if ( projectInformation.getDownloadUrl() != null ) - { - pkg.setDownloadLocation( projectInformation.getDownloadUrl() ); - } - // archive file name - if ( projectInformation.getPackageArchiveFileName() != null ) - { - pkg.setPackageFileName( projectInformation.getPackageArchiveFileName() ); - } - // home page - if ( projectInformation.getHomePage() != null ) - { - try - { - pkg.setHomepage( projectInformation.getHomePage() ); - } - catch( InvalidSPDXAnalysisException ex ) - { - LOG.warn( "Invalid URL in project POM file: "+projectInformation.getHomePage() ); - } - - } - // source information - if ( projectInformation.getSourceInfo() != null ) - { - pkg.setSourceInfo( projectInformation.getSourceInfo() ); - } - // license comment - if ( projectInformation.getLicenseComment() != null ) - { - pkg.setLicenseComments( projectInformation.getLicenseComment() ); - } - // originator - if ( projectInformation.getOriginator() != null ) - { - pkg.setOriginator( projectInformation.getOriginator() ); - } - // short description - if ( projectInformation.getShortDescription() != null ) - { - pkg.setSummary( projectInformation.getShortDescription() ); - } - // supplier - if ( projectInformation.getSupplier() != null ) - { - pkg.setSupplier( projectInformation.getSupplier() ); - } - // version info - if ( projectInformation.getVersionInfo() != null ) - { - pkg.setVersionInfo( projectInformation.getVersionInfo() ); - } - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error adding package properties", e ); - } - - // sha1 checksum - if ( projectInformation.getChecksums() != null ) - { - try - { - pkg.getChecksums().addAll( projectInformation.getChecksums() ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( - "Error adding package information to SPDX document - Invalid checksum provided", e ); - } - } - // external references - ExternalReference[] externalRefs = projectInformation.getExternalRefs(); - if ( externalRefs != null && externalRefs.length > 0 ) - { - for ( ExternalReference externalRef : externalRefs ) - { - try - { - pkg.getExternalRefs().add( externalRef.convertExternalRef( spdxDoc ) ); - } - catch ( MojoExecutionException | InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( - "Error adding package information to SPDX document - Invalid external refs provided", e ); - } - } - } - return pkg; - } - - /** - * Fill in the creator information to the SPDX document - * - * @param projectInformation project level information including the creators - * @throws InvalidSPDXAnalysisException - */ - private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws InvalidSPDXAnalysisException - { - ArrayList creators = new ArrayList<>(); - String[] parameterCreators = projectInformation.getCreators(); - for ( String parameterCreator : parameterCreators ) - { - String verify = SpdxVerificationHelper.verifyCreator( parameterCreator ); - if ( verify == null ) - { - creators.add( parameterCreator ); - } - else - { - LOG.warn( - "Invalid creator string ( " + verify + " ), " + parameterCreator + " will be skipped." ); - } - } - SpdxCreatorInformation spdxCreator = spdxDoc.createCreationInfo( creators, format.format( new Date() ) ); - spdxCreator.setComment( projectInformation.getCreatorComment() ); - spdxCreator.setLicenseListVersion( ListedLicenses.getListedLicenses().getLicenseListVersion() ); - spdxDoc.setCreationInfo( spdxCreator ); - } - - /** - * Collect information at the file level, fill in the SPDX document - * - * @param sources Source directories to be included in the document - * @param baseDir project base directory used to construct the relative paths for the SPDX - * files - * @param pathSpecificInformation Map of path to file information used to override the default file information - * @param algorithms algorithms to use to generate checksums - * @throws SpdxBuilderException - */ - public void collectSpdxFileInformation( List sources, String baseDir, - SpdxDefaultFileInformation defaultFileInformation, - Map pathSpecificInformation, - Set algorithms ) throws SpdxBuilderException - { - SpdxFileCollector fileCollector = new SpdxFileCollector(); - try - { - fileCollector.collectFiles( sources, baseDir, defaultFileInformation, - pathSpecificInformation, projectPackage, RelationshipType.GENERATES, spdxDoc, algorithms ); - projectPackage.getFiles().addAll( fileCollector.getFiles() ); - projectPackage.getLicenseInfoFromFiles().addAll( fileCollector.getLicenseInfoFromFiles() ); - } - catch ( SpdxCollectionException|InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Error collecting SPDX file information", e ); - } - try - { - String spdxFileName = spdxFile.getPath().replace( "\\", "/" ); - projectPackage.setPackageVerificationCode( fileCollector.getVerificationCode( spdxFileName, spdxDoc ) ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new SpdxBuilderException( "Unable to calculate verification code", e ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxBuilderException( "Unable to update verification code", e ); - } - } - - public SpdxV2LicenseManager getLicenseManager() - { - return this.licenseManager; - } - - public SpdxPackage getProjectPackage() - { - return projectPackage; - } - -} diff --git a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java deleted file mode 100644 index c018abb..0000000 --- a/src/main/java/org/spdx/maven/utils/SpdxFileCollector.java +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Copyright 2014 Source Auditor Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License" ); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.spdx.maven.utils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.*; -import java.util.Map.Entry; - -import org.apache.maven.shared.model.fileset.FileSet; -import org.apache.maven.shared.model.fileset.util.FileSetManager; -import org.spdx.core.CoreModelObject; -import org.spdx.core.InvalidSPDXAnalysisException; -import org.spdx.maven.Checksum; -import org.spdx.maven.SnippetInfo; -import org.spdx.storage.IModelStore.IdType; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Collects SPDX file information from directories. - *

- * The method collectFilesInDirectory(FileSet[] filesets) will scan and create SPDX File information for - * all files in the filesets. - * - * @author Gary O'Neall - */ -public class SpdxFileCollector -{ - private static final Logger LOG = LoggerFactory.getLogger( SpdxFileCollector.class ); - - // constants for mapping extensions to types. - static final String SPDX_FILE_TYPE_CONSTANTS_PROP_PATH = "resources/SpdxFileTypeConstants.prop"; - - static final Map EXT_TO_FILE_TYPE = new HashMap<>(); - - static - { - loadFileExtensionConstants(); - } - - static final Map checksumAlgorithms = new HashMap<>(); - - static - { - checksumAlgorithms.put( ChecksumAlgorithm.SHA1, "SHA-1" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA224, "SHA-224" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA256, "SHA-256" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA384, "SHA-384" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA3_384, "SHA-512" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD2, "MD2" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD4, "MD4" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD5, "MD5" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD6, "MD6" ); - } - - Set licensesFromFiles = new HashSet<>(); - /** - * Map of fileName, SPDXFile for all files in the SPDX document - */ - Map spdxFiles = new HashMap<>(); - List spdxSnippets = new ArrayList<>(); - - FileSetManager fileSetManager = new FileSetManager(); - - /** - * SpdxFileCollector collects SPDX file information for files - */ - public SpdxFileCollector() - { - } - - /** - * Load file type constants from the properties file - */ - private static void loadFileExtensionConstants() - { - Properties prop = new Properties(); - try ( InputStream is = SpdxFileCollector.class.getClassLoader().getResourceAsStream( - SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ) ) - { - if ( is == null ) - { - LOG.error( "Unable to load properties file " + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ); - return; - } - prop.load( is ); - Iterator> iter = prop.entrySet().iterator(); - while ( iter.hasNext() ) - { - Entry entry = iter.next(); - String fileTypeStr = (String)entry.getKey(); - FileType fileType = FileType.valueOf( fileTypeStr ); - String[] extensions = ((String)entry.getValue()).split( "," ); - for ( String extension:extensions ) - { - try - { - String trimmedExtension = extension.toUpperCase().trim(); - if ( EXT_TO_FILE_TYPE.containsKey( trimmedExtension ) ) - { - LOG.warn( "Duplicate file extension: "+trimmedExtension ); - } - EXT_TO_FILE_TYPE.put( trimmedExtension, fileType ); - } - catch ( Exception ex ) { - LOG.error( "Error adding file extensions to filetype map", ex ); - } - } - } - } - catch ( IOException e ) - { - LOG.warn( - "WARNING: Error reading SpdxFileTypeConstants properties file. All file types will be mapped to Other." ); - } - } - - /** - * Collect file information in the directory (including subdirectories). - * - * @param fileSets FileSets containing the description of the directory to be scanned - * @param baseDir project base directory used to construct the relative paths for the SPDX files - * @param defaultFileInformation Information on default SPDX field data for the files - * @param pathSpecificInformation Map of path to file information used to override the default file information - * @param relationshipType Type of relationship to the project package - * @param projectPackage Package to which the files belong - * @param spdxDoc SPDX document which contains the extracted license infos that may be needed for license parsing - * - * @throws SpdxCollectionException - */ - public void collectFiles( List fileSets, String baseDir, - SpdxDefaultFileInformation defaultFileInformation, - Map pathSpecificInformation, - SpdxPackage projectPackage, RelationshipType relationshipType, - SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException - { - for ( FileSet fileSet : fileSets ) - { - String[] includedFiles = fileSetManager.getIncludedFiles( fileSet ); - for ( String includedFile : includedFiles ) - { - String filePath = fileSet.getDirectory() + File.separator + includedFile; - File file = new File( filePath ); - String relativeFilePath = file.getAbsolutePath().substring( baseDir.length() + 1 ).replace( '\\', '/' ); - SpdxDefaultFileInformation fileInfo = findDefaultFileInformation( relativeFilePath, - pathSpecificInformation ); - if ( fileInfo == null ) - { - fileInfo = defaultFileInformation; - } - - String outputFileName; - if ( fileSet.getOutputDirectory() != null ) - { - outputFileName = fileSet.getOutputDirectory() + File.separator + includedFile; - } - else - { - outputFileName = file.getAbsolutePath().substring( baseDir.length() + 1 ); - } - collectFile( file, outputFileName, fileInfo, relationshipType, projectPackage, spdxDoc, algorithms ); - } - } - } - - /** - * Find the most appropriate file information based on the lowest level match (closed to file) - * - * @param filePath - * @param pathSpecificInformation - * @return - */ - private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, Map pathSpecificInformation ) - { - LOG.debug( "Checking for file path " + filePath ); - SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); - if ( retval != null ) - { - LOG.debug( "Found filepath" ); - return retval; - } - // see if any of the parent directories contain default information which should be used - String parentPath = filePath; - int parentPathIndex = 0; - do - { - parentPathIndex = parentPath.lastIndexOf( "/" ); - if ( parentPathIndex > 0 ) - { - parentPath = parentPath.substring( 0, parentPathIndex ); - retval = pathSpecificInformation.get( parentPath ); - } - } while ( retval == null && parentPathIndex > 0 ); - if ( retval != null ) - { - LOG.debug( "Found directory containing file path for path specific information. File path: " + parentPath ); - } - return retval; - } - - /** - * Collect SPDX information for a specific file - * - * @param file - * @param outputFileName Path to the output file name relative to the root of the output archive file - * @param relationshipType Type of relationship to the project package - * @param projectPackage Package to which the files belong - * @param spdxDoc SPDX Document which will contain the files - * @param algorithms algorithms to use to generate checksums - * @throws SpdxCollectionException - */ - private void collectFile( File file, String outputFileName, SpdxDefaultFileInformation fileInfo, RelationshipType relationshipType, SpdxPackage projectPackage, SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException - { - if ( spdxFiles.containsKey( file.getPath() ) ) - { - return; // already added from a previous scan - } - SpdxFile spdxFile = convertToSpdxFile( file, outputFileName, fileInfo, algorithms, spdxDoc ); - try - { - Relationship relationship = spdxDoc.createRelationship( projectPackage, relationshipType, "" ); - spdxFile.addRelationship( relationship ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxCollectionException( "Error creating SPDX file relationship", e ); - } - if ( fileInfo.getSnippets() != null ) - { - for ( SnippetInfo snippet : fileInfo.getSnippets() ) - { - SpdxSnippet spdxSnippet; - try - { - spdxSnippet = convertToSpdxSnippet( snippet, spdxFile, spdxDoc ); - } - catch ( InvalidLicenseStringException e ) - { - throw new SpdxCollectionException( - "Error processing SPDX snippet information. Invalid license string specified in snippet.", - e ); - } - catch ( SpdxBuilderException e ) - { - throw new SpdxCollectionException( "Error creating SPDX snippet information.", e ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxCollectionException( - "Error processing SPDX snippet information.", - e ); - } - spdxSnippets.add( spdxSnippet ); - } - } - spdxFiles.put( file.getPath(), spdxFile ); - Collection licenseInfoFromFiles; - try - { - licenseInfoFromFiles = spdxFile.getLicenseInfoFromFiles(); - licensesFromFiles.addAll( licenseInfoFromFiles ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxCollectionException( "Error getting license information from files.", e ); - } - } - - /** - * Create an SpdxSnippet from the snippet information provided - * @param snippet - * @param spdxFile - * @param spdxDoc - * @return - * @throws SpdxBuilderException - * @throws InvalidSPDXAnalysisException - */ - private SpdxSnippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile, SpdxDocument spdxDoc ) throws SpdxBuilderException, InvalidSPDXAnalysisException - { - //TODO: Add annotations to snippet - return spdxDoc.createSpdxSnippet( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri() ), - snippet.getName(), snippet.getLicenseConcluded( spdxDoc ), - snippet.getLicenseInfoInSnippet( spdxDoc ), - snippet.getCopyrightText(), spdxFile, - snippet.getByteRangeStart(), snippet.getByteRangeEnd() ) - .setComment( snippet.getComment() ) - .setLicenseComments( snippet.getLicensComment() ) - .setLineRange( snippet.getLineRangeStart(), snippet.getLineRangeEnd() ) - .build(); - } - - /** - * @param file - * @param outputFileName Path to the output file name relative to the root of the output archive file - * @param defaultFileInformation Information on default SPDX field data for the files - * @param algorithms algorithms to use to generate checksums - * @param spdxDoc SPDX document which will contain the SPDX file - * @return - * @throws SpdxCollectionException - */ - private SpdxFile convertToSpdxFile( File file, String outputFileName, - SpdxDefaultFileInformation defaultFileInformation, - Set algorithms, - SpdxDocument spdxDoc ) throws SpdxCollectionException - { - String relativePath = convertFilePathToSpdxFileName( outputFileName ); - ArrayList fileTypes = new ArrayList<>(); - fileTypes.add( extensionToFileType( getExtension( file ) ) ); - Set checksums; - try - { - checksums = generateChecksum( file, algorithms, spdxDoc ); - } - catch ( SpdxCollectionException | InvalidSPDXAnalysisException e1 ) - { - throw new SpdxCollectionException( "Unable to generate checksum for file "+file.getName() ); - } - AnyLicenseInfo concludedLicense = null; - AnyLicenseInfo license = null; - String licenseComment = defaultFileInformation.getLicenseComment(); - if ( isSourceFile( fileTypes ) && file.length() < SpdxSourceFileParser.MAXIMUM_SOURCE_FILE_LENGTH ) - { - List fileSpdxLicenses = null; - try - { - fileSpdxLicenses = SpdxSourceFileParser.parseFileForSpdxLicenses( file ); - } - catch ( SpdxSourceParserException ex ) - { - LOG.error( "Error parsing for SPDX license ID's", ex ); - } - if ( fileSpdxLicenses != null && fileSpdxLicenses.size() > 0 ) - { - // The file has declared licenses of the form SPDX-License-Identifier: licenseId - if ( fileSpdxLicenses.size() == 1 ) - { - license = fileSpdxLicenses.get( 0 ); - } - else - { - try - { - license = spdxDoc.createConjunctiveLicenseSet( fileSpdxLicenses ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxCollectionException( "Error creating SPDX file - unable to create a license set", e ); - } - } - if ( licenseComment == null ) - { - licenseComment = ""; - } - else if ( licenseComment.length() > 0 ) - { - licenseComment = licenseComment.concat( "; " ); - } - licenseComment = licenseComment.concat( "This file contains SPDX-License-Identifiers for " ); - licenseComment = licenseComment.concat( license.toString() ); - } - } - if ( license == null ) - { - license = defaultFileInformation.getDeclaredLicense(); - concludedLicense = defaultFileInformation.getConcludedLicense(); - } - else - { - concludedLicense = license; - } - - String copyright = defaultFileInformation.getCopyright(); - String notice = defaultFileInformation.getNotice(); - String comment = defaultFileInformation.getComment(); - String[] defaultContributors = defaultFileInformation.getContributors(); - List contributors; - if ( defaultContributors != null ) { - contributors = Arrays.asList( defaultFileInformation.getContributors() ); - } else { - contributors = new ArrayList<>(); - } - - SpdxFile retval = null; - //TODO: Add annotation - try - { - List seenLicenses = new ArrayList<>(); - seenLicenses.add( license ); - Checksum sha1 = null; - for ( Checksum checksum:checksums ) - { - if (ChecksumAlgorithm.SHA1.equals( checksum.getAlgorithm() )) { - sha1 = checksum; - break; - } - } - retval = spdxDoc.createSpdxFile( spdxDoc.getModelStore().getNextId( IdType.SpdxId, spdxDoc.getDocumentUri() ), - relativePath, concludedLicense, seenLicenses, - copyright, sha1 ) - .setComment( comment ) - .setLicenseComments( licenseComment ) - .setFileTypes( fileTypes ) - .setFileContributors( contributors ) - .build(); - - - retval.setNoticeText( notice ); - } - catch ( InvalidSPDXAnalysisException e ) - { - throw new SpdxCollectionException( "Error creating SPDX file", e ); - } - - return retval; - } - - /** - * @param fileTypes - * @return true if the fileTypes contain a source file type - */ - protected boolean isSourceFile( Collection fileTypes ) - { - for ( FileType ft : fileTypes ) - { - if ( ft == FileType.SOURCE ) - { - return true; - } - } - return false; - } - - /** - * Create the SPDX file name from a system specific path name - * - * @param filePath system specific file path relative to the top of the archive root to the top of the archive - * directory where the file is stored. - * @return - */ - public String convertFilePathToSpdxFileName( String filePath ) - { - String result = filePath.replace( '\\', '/' ); - if ( !result.startsWith( "./" ) ) - { - result = "./" + result; - } - return result; - } - - public String getExtension( File file ) - { - String fileName = file.getName(); - int lastDot = fileName.lastIndexOf( '.' ); - if ( lastDot < 1 ) - { - return ""; - } - else - { - return fileName.substring( lastDot + 1 ); - } - } - - protected static FileType extensionToFileType( String fileExtension ) - { - FileType retval = EXT_TO_FILE_TYPE.get( fileExtension.trim().toUpperCase() ); - if ( retval == null ) - { - retval = FileType.OTHER; - } - return retval; - } - - /** - * @return SPDX Files which have been acquired through the collectFilesInDirectory method - */ - public Collection getFiles() - { - return spdxFiles.values(); - } - - /** - * @return SPDX Snippets collected through the collectFilesInDirectory method - */ - public List getSnippets() - { - return this.spdxSnippets; - } - - /** - * @return all license information used in the SPDX files - */ - public Collection getLicenseInfoFromFiles() - { - return licensesFromFiles; - } - - /** - * Create a verification code from all SPDX files collected - * - * @param spdxFilePath Complete file path for the SPDX file - this will be excluded from the verification code - * @param spdxDoc SPDX document which will contain the package verification code. - * @return - * @throws NoSuchAlgorithmException - * @throws InvalidSPDXAnalysisException - */ - public SpdxPackageVerificationCode getVerificationCode( String spdxFilePath, SpdxDocument spdxDoc ) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException - { - List excludedFileNamesFromVerificationCode = new ArrayList<>(); - - if ( spdxFilePath != null && spdxFiles.containsKey( spdxFilePath ) ) - { - Optional excludedFileName = spdxFiles.get( spdxFilePath ).getName(); - if ( excludedFileName.isPresent() ) - { - excludedFileNamesFromVerificationCode.add( excludedFileName.get() ); - } - } - SpdxPackageVerificationCode verificationCode; - verificationCode = calculatePackageVerificationCode( spdxFiles.values(), - excludedFileNamesFromVerificationCode, spdxDoc ); - return verificationCode; - } - - /** - * Calculate the package verification code for a collection of SPDX files - * - * @param spdxFiles Files used to calculate the verification code - * @param excludedFileNamesFromVerificationCode List of file names to exclude - * @param spdxDoc SPDX document which will contain the Package Verification Code - * @return - * @throws NoSuchAlgorithmException - * @throws InvalidSPDXAnalysisException - */ - private SpdxPackageVerificationCode calculatePackageVerificationCode( Collection spdxFiles, - List excludedFileNamesFromVerificationCode, - SpdxDocument spdxDoc ) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException - { - List fileChecksums = new ArrayList<>(); - for ( SpdxFile file : spdxFiles ) - { - Optional filename = file.getName(); - if ( filename.isPresent() && includeInVerificationCode( file.getName().get(), excludedFileNamesFromVerificationCode ) ) - { - fileChecksums.add( file.getSha1() ); - } - } - Collections.sort( fileChecksums ); - MessageDigest verificationCodeDigest = MessageDigest.getInstance( "SHA-1" ); - for ( String fileChecksum : fileChecksums ) - { - byte[] hashInput = fileChecksum.getBytes( StandardCharsets.UTF_8 ); - verificationCodeDigest.update( hashInput ); - } - String value = convertChecksumToString( verificationCodeDigest.digest() ); - return spdxDoc.createPackageVerificationCode( value, excludedFileNamesFromVerificationCode ); - } - - private boolean includeInVerificationCode( String name, List excludedFileNamesFromVerificationCode ) - { - for ( String s : excludedFileNamesFromVerificationCode ) - { - if ( s.equals( name ) ) - { - return false; - } - } - return true; - } - - /** - * Converts an array of bytes to a string compliant with the SPDX sha1 representation - * - * @param digestBytes - * @return - */ - public static String convertChecksumToString( byte[] digestBytes ) - { - StringBuilder sb = new StringBuilder(); - for ( byte digestByte : digestBytes ) - { - String hex = Integer.toHexString( 0xff & digestByte ); - if ( hex.length() < 2 ) - { - sb.append( '0' ); - } - sb.append( hex ); - } - return sb.toString(); - } - - /** - * Generate the Sha1 for a given file. Must have read access to the file. This method is equivalent to calling - * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. - * - * @param file file to generate checksum for - * @param builder Builder for the SPDX document that will contain the checksum - * @return SHA1 checksum of the input file - * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read - * @throws InvalidSPDXAnalysisException - */ - public static CoreModelObject generateSha1( File file, AbstractDocumentBuilder builder ) throws SpdxCollectionException, InvalidSPDXAnalysisException - { - Set sha1 = new HashSet<>(); - sha1.add( "SHA-1" ); - return generateChecksum( file, sha1, builder ).iterator().next(); - } - - /** - * Generate checksums for a given file using each algorithm supplied. Must have read access to the file. - * - * @param file file whose checksum is to be generated - * @param algorithms algorithms to generate the checksums - * @param spdxDoc SPDX document which will contain the checksum - * @return {@code Set} of checksums for file using each algorithm specified - * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read - * @throws InvalidSPDXAnalysisException - */ - public static Set generateChecksum( File file, Set algorithms, - AbstractDocumentBuilder builder ) throws SpdxCollectionException, InvalidSPDXAnalysisException - { - Set checksums = new HashSet<>(); - - byte[] buffer; - try - { - buffer = Files.readAllBytes( file.toPath() ); - } - catch ( IOException e ) - { - throw new SpdxCollectionException( "IO error while calculating checksums.", e ); - } - - for ( String algorithm : algorithms ) - { - String checksumAlgorithm = checksumAlgorithms.get( algorithm ); - - MessageDigest digest; - try - { - digest = MessageDigest.getInstance( checksumAlgorithm ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new SpdxCollectionException( e ); - } - - digest.update( buffer ); - String checksum = convertChecksumToString( digest.digest() ); - checksums.add( new Checksum( algorithm, checksum ) ); - } - - return checksums; - } -} diff --git a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java index d7adee8..6840f60 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java @@ -17,15 +17,10 @@ import java.util.Set; -import org.spdx.core.CoreModelObject; -import org.spdx.core.InvalidSPDXAnalysisException; - import org.spdx.maven.Annotation; import org.spdx.maven.Checksum; import org.spdx.maven.ExternalReference; import org.spdx.maven.Packaging; -import org.spdx.storage.IModelStore; -import org.spdx.storage.PropertyDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -334,29 +329,6 @@ public void setName( String name ) { this.name = name; } - - /** - * Log information on all fields - typically used for debugging - * @throws InvalidSPDXAnalysisException - */ - public static void logInfo( CoreModelObject modelObject ) throws InvalidSPDXAnalysisException - { - if ( !LOG.isDebugEnabled() ) { - return; - } - IModelStore store = modelObject.getModelStore(); - String objectUri = modelObject.getObjectUri(); - for ( PropertyDescriptor desc : store.getPropertyValueDescriptors( objectUri ) ) { - if (store.isCollectionProperty( objectUri, desc )) { - //TODO Implement - } - else - { - //TODO Implement - } - } - //TODO for SPDX V3 - log al relationships from this object - } /** * Log information on all fields - typically used for debugging diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java index b899aed..6129301 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java @@ -47,6 +47,7 @@ import org.spdx.library.model.v2.SpdxElement; import org.spdx.library.model.v2.SpdxPackage; import org.spdx.library.model.v2.enumerations.AnnotationType; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; import org.spdx.library.model.v2.enumerations.Purpose; import org.spdx.library.model.v2.enumerations.RelationshipType; import org.spdx.library.model.v2.license.AnyLicenseInfo; @@ -154,7 +155,6 @@ protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument external private List documentAnnotations = new ArrayList<>(); private SpdxDocument spdxDoc; private SpdxV2LicenseManager licenseManager; - private SpdxV2DocumentBuilder builder; /** * @param builder The document builder @@ -168,7 +168,6 @@ public SpdxV2DependencyBuilder( SpdxV2DocumentBuilder builder, boolean createExt boolean includeTransitiveDependencies ) { super( createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); - this.builder = builder; this.spdxDoc = builder.getSpdxDoc(); this.licenseManager = builder.getLicenseManager(); } @@ -482,7 +481,9 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd { String externalRefDocId = SpdxConstantsCompatV2.EXTERNAL_DOC_REF_PRENUM + fixExternalRefId( fullArtifactId ); LOG.debug( "Creating external document ref " + externalDocNamespace ); - Checksum cksum = (Checksum)SpdxFileCollector.generateSha1( spdxFile, builder ); + org.spdx.maven.Checksum mavenChecksum = AbstractFileCollector.generateSha1( spdxFile ); + Checksum cksum = spdxDoc.createChecksum( ChecksumAlgorithm.valueOf( mavenChecksum.getAlgorithm() ), + mavenChecksum.getValue() ); externalRef = spdxDoc.createExternalDocumentRef( externalRefDocId, externalSpdxDoc.getDocumentUri(), cksum ); spdxDoc.getExternalDocumentRefs().add( externalRef ); org.spdx.library.model.v2.Annotation docRefAddedAnnotation = spdxDoc.createAnnotation( "Tool: spdx-maven-plugin", diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java index 914f66d..1f93cef 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -495,15 +495,13 @@ public ExternalRef convertExternalRef( ExternalReference externalReference ) thr @Override public CoreModelObject getProjectPackage() { - // TODO Auto-generated method stub - return null; + return projectPackage; } @Override - public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) throws LicenseManagerException { - // TODO Auto-generated method stub - return null; + return licenseManager.mavenLicenseListToSpdxLicense( mavenLicenses ).toString(); } @Override diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java index 9ed96d1..f3af478 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -16,14 +16,10 @@ package org.spdx.maven.utils; import java.io.File; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; -import java.util.Map.Entry; import org.apache.maven.shared.model.fileset.FileSet; import org.apache.maven.shared.model.fileset.util.FileSetManager; @@ -44,47 +40,17 @@ import org.spdx.maven.SnippetInfo; import org.spdx.storage.IModelStore.IdType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * Collects SPDX file information from directories. + * Collects SPDX file information from directories in SPDX Spec version 2 format *

* The method collectFilesInDirectory(FileSet[] filesets) will scan and create SPDX File information for * all files in the filesets. * * @author Gary O'Neall */ -public class SpdxV2FileCollector +public class SpdxV2FileCollector extends AbstractFileCollector { - private static final Logger LOG = LoggerFactory.getLogger( SpdxV2FileCollector.class ); - - // constants for mapping extensions to types. - static final String SPDX_FILE_TYPE_CONSTANTS_PROP_PATH = "resources/SpdxFileTypeConstants.prop"; - - static final Map EXT_TO_FILE_TYPE = new HashMap<>(); - - static - { - loadFileExtensionConstants(); - } - - static final Map checksumAlgorithms = new HashMap<>(); - - static - { - checksumAlgorithms.put( ChecksumAlgorithm.SHA1.toString(), "SHA-1" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA224.toString(), "SHA-224" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA256.toString(), "SHA-256" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA384.toString(), "SHA-384" ); - checksumAlgorithms.put( ChecksumAlgorithm.SHA3_384.toString(), "SHA-512" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD2.toString(), "MD2" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD4.toString(), "MD4" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD5.toString(), "MD5" ); - checksumAlgorithms.put( ChecksumAlgorithm.MD6.toString(), "MD6" ); - } - Set licensesFromFiles = new HashSet<>(); /** * Map of fileName, SPDXFile for all files in the SPDX document @@ -101,52 +67,6 @@ public SpdxV2FileCollector() { } - /** - * Load file type constants from the properties file - */ - private static void loadFileExtensionConstants() - { - Properties prop = new Properties(); - try ( InputStream is = SpdxV2FileCollector.class.getClassLoader().getResourceAsStream( - SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ) ) - { - if ( is == null ) - { - LOG.error( "Unable to load properties file " + SPDX_FILE_TYPE_CONSTANTS_PROP_PATH ); - return; - } - prop.load( is ); - Iterator> iter = prop.entrySet().iterator(); - while ( iter.hasNext() ) - { - Entry entry = iter.next(); - String fileTypeStr = (String)entry.getKey(); - FileType fileType = FileType.valueOf( fileTypeStr ); - String[] extensions = ((String)entry.getValue()).split( "," ); - for ( String extension:extensions ) - { - try - { - String trimmedExtension = extension.toUpperCase().trim(); - if ( EXT_TO_FILE_TYPE.containsKey( trimmedExtension ) ) - { - LOG.warn( "Duplicate file extension: "+trimmedExtension ); - } - EXT_TO_FILE_TYPE.put( trimmedExtension, fileType ); - } - catch ( Exception ex ) { - LOG.error( "Error adding file extensions to filetype map", ex ); - } - } - } - } - catch ( IOException e ) - { - LOG.warn( - "WARNING: Error reading SpdxFileTypeConstants properties file. All file types will be mapped to Other." ); - } - } - /** * Collect file information in the directory (including subdirectories). * @@ -312,9 +232,16 @@ private void collectFile( File file, String outputFileName, SpdxDefaultFileInfor private SpdxSnippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile, SpdxDocument spdxDoc ) throws SpdxBuilderException, InvalidSPDXAnalysisException { //TODO: Add annotations to snippet + AnyLicenseInfo concludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( snippet.getLicenseConcluded(), spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); + List licenseInfoInSnippet = new ArrayList<>(); + licenseInfoInSnippet.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( snippet.getLicenseInfoInSnippet(), + spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ) ); return spdxDoc.createSpdxSnippet( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), - snippet.getName(), snippet.getLicenseConcluded( spdxDoc ), - snippet.getLicenseInfoInSnippet( spdxDoc ), + snippet.getName(), concludedLicense, + licenseInfoInSnippet, snippet.getCopyrightText(), spdxFile, snippet.getByteRangeStart(), snippet.getByteRangeEnd() ) .setComment( snippet.getComment() ) @@ -461,62 +388,7 @@ else if ( licenseComment.length() > 0 ) return retval; } - /** - * @param fileTypes - * @return true if the fileTypes contain a source file type - */ - protected boolean isSourceFile( Collection fileTypes ) - { - for ( FileType ft : fileTypes ) - { - if ( ft == FileType.SOURCE ) - { - return true; - } - } - return false; - } - - /** - * Create the SPDX file name from a system specific path name - * - * @param filePath system specific file path relative to the top of the archive root to the top of the archive - * directory where the file is stored. - * @return - */ - public String convertFilePathToSpdxFileName( String filePath ) - { - String result = filePath.replace( '\\', '/' ); - if ( !result.startsWith( "./" ) ) - { - result = "./" + result; - } - return result; - } - - public String getExtension( File file ) - { - String fileName = file.getName(); - int lastDot = fileName.lastIndexOf( '.' ); - if ( lastDot < 1 ) - { - return ""; - } - else - { - return fileName.substring( lastDot + 1 ); - } - } - - protected static FileType extensionToFileType( String fileExtension ) - { - FileType retval = EXT_TO_FILE_TYPE.get( fileExtension.trim().toUpperCase() ); - if ( retval == null ) - { - retval = FileType.OTHER; - } - return retval; - } + /** * @return SPDX Files which have been acquired through the collectFilesInDirectory method @@ -614,87 +486,4 @@ private boolean includeInVerificationCode( String name, List excludedFil } return true; } - - /** - * Converts an array of bytes to a string compliant with the SPDX sha1 representation - * - * @param digestBytes - * @return - */ - public static String convertChecksumToString( byte[] digestBytes ) - { - StringBuilder sb = new StringBuilder(); - for ( byte digestByte : digestBytes ) - { - String hex = Integer.toHexString( 0xff & digestByte ); - if ( hex.length() < 2 ) - { - sb.append( '0' ); - } - sb.append( hex ); - } - return sb.toString(); - } - - /** - * Generate the Sha1 for a given file. Must have read access to the file. This method is equivalent to calling - * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. - * - * @param file file to generate checksum for - * @param builder Builder for the SPDX document that will contain the checksum - * @return SHA1 checksum of the input file - * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read - * @throws InvalidSPDXAnalysisException - */ - public static Checksum generateSha1( File file ) throws SpdxCollectionException, InvalidSPDXAnalysisException - { - Set sha1 = new HashSet<>(); - sha1.add( "SHA-1" ); - return generateChecksum( file, sha1 ).iterator().next(); - } - - /** - * Generate checksums for a given file using each algorithm supplied. Must have read access to the file. - * - * @param file file whose checksum is to be generated - * @param algorithms algorithms to generate the checksums - * @return {@code Set} of checksums for file using each algorithm specified - * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read - * @throws InvalidSPDXAnalysisException - */ - public static Set generateChecksum( File file, Set algorithms ) throws SpdxCollectionException, InvalidSPDXAnalysisException - { - Set checksums = new HashSet<>(); - - byte[] buffer; - try - { - buffer = Files.readAllBytes( file.toPath() ); - } - catch ( IOException e ) - { - throw new SpdxCollectionException( "IO error while calculating checksums.", e ); - } - - for ( String algorithm : algorithms ) - { - String checksumAlgorithm = checksumAlgorithms.get( algorithm ); - - MessageDigest digest; - try - { - digest = MessageDigest.getInstance( checksumAlgorithm ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new SpdxCollectionException( e ); - } - - digest.update( buffer ); - String checksum = convertChecksumToString( digest.digest() ); - checksums.add( new Checksum( algorithm, checksum ) ); - } - - return checksums; - } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java index b586974..a453597 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java @@ -38,6 +38,7 @@ import org.spdx.library.conversion.Spdx2to3Converter; import org.spdx.library.model.v2.Checksum; import org.spdx.library.model.v2.SpdxPackageVerificationCode; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; import org.spdx.library.model.v2.enumerations.Purpose; import org.spdx.library.model.v3_0_1.SpdxConstantsV3; import org.spdx.library.model.v3_0_1.core.Agent; @@ -75,7 +76,6 @@ public class SpdxV3DependencyBuilder { private SpdxDocument spdxDoc; private SpdxV3LicenseManager licenseManager; - private SpdxV3DocumentBuilder builder; /** * @param builder The document builder @@ -89,7 +89,6 @@ public SpdxV3DependencyBuilder( SpdxV3DocumentBuilder builder, boolean createExt boolean includeTransitiveDependencies ) { super( createExternalRefs, generatePurls, useArtifactID, includeTransitiveDependencies ); - this.builder = builder; this.spdxDoc = builder.getSpdxDoc(); this.licenseManager = builder.getLicenseManager(); } @@ -505,11 +504,11 @@ private Element copyPackageInfoFromV2File( String path, String groupId, String a { CreationInfo creationInfo = new CreationInfo.CreationInfoBuilder( dest.getModelStore(), dest.getModelStore().getNextId(IdType.Anonymous), - null) - .setCreated(fromAnnotation.getAnnotationDate()) - .setSpecVersion(SpdxConstantsV3.MODEL_SPEC_VERSION) + null ) + .setCreated( fromAnnotation.getAnnotationDate() ) + .setSpecVersion( SpdxConstantsV3.MODEL_SPEC_VERSION ) .build(); - creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent(fromAnnotation.getAnnotator(), creationInfo) ); + creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( fromAnnotation.getAnnotator(), creationInfo ) ); dest.createAnnotation( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) .setAnnotationType( Spdx2to3Converter.ANNOTATION_TYPE_MAP.get( fromAnnotation.getAnnotationType() ) ) .setStatement( fromAnnotation.getComment() ) @@ -599,6 +598,7 @@ else if ( licenseComments.isEmpty() ) .setFrom( dest ) .addTo( packageFile ) .setRelationshipType( RelationshipType.HAS_DISTRIBUTION_ARTIFACT ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) .build(); } Optional primaryPurpose = source.getPrimaryPurpose(); @@ -695,7 +695,13 @@ else if ( root instanceof Sbom ) return retval; // No need to create the external map } } - Hash hash = (Hash)SpdxFileCollector.generateSha1( spdxFile, builder ); + org.spdx.maven.Checksum checksum = AbstractFileCollector.generateSha1( spdxFile ); + final HashAlgorithm algorithm = Spdx2to3Converter.HASH_ALGORITH_MAP.get( ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ) ); + Hash hash = spdxDoc.createHash( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .setAlgorithm( algorithm ) + .setHashValue( checksum.getValue() ) + .build(); + StringBuilder sb = new StringBuilder( groupId ).append( artifactId ); if ( Objects.nonNull( version )) { sb.append( version ); diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index 8f7e39d..cb4fffc 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -9,21 +9,49 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.Set; import org.apache.maven.model.License; +import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.model.fileset.FileSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.spdx.core.CoreModelObject; import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.conversion.Spdx2to3Converter; +import org.spdx.library.model.v2.ReferenceType; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.ReferenceCategory; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; import org.spdx.library.model.v3_0_1.SpdxModelClassFactoryV3; +import org.spdx.library.model.v3_0_1.core.AnnotationType; import org.spdx.library.model.v3_0_1.core.CreationInfo; +import org.spdx.library.model.v3_0_1.core.DictionaryEntry; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.core.HashAlgorithm; +import org.spdx.library.model.v3_0_1.core.Relationship; +import org.spdx.library.model.v3_0_1.core.RelationshipCompleteness; +import org.spdx.library.model.v3_0_1.core.RelationshipType; import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; import org.spdx.library.model.v3_0_1.software.Sbom; +import org.spdx.library.model.v3_0_1.software.SoftwareArtifact; +import org.spdx.library.model.v3_0_1.software.SoftwarePurpose; +import org.spdx.library.model.v3_0_1.software.SpdxFile; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.library.referencetype.ListedReferenceTypes; +import org.spdx.maven.Checksum; +import org.spdx.maven.ExternalReference; import org.spdx.maven.NonStandardLicense; import org.spdx.maven.OutputFormat; +import org.spdx.maven.Packaging; +import org.spdx.storage.IModelStore.IdType; import org.spdx.storage.simple.InMemSpdxStore; import org.spdx.v3jsonldstore.JsonLDStore; @@ -36,10 +64,17 @@ public class SpdxV3DocumentBuilder extends AbstractDocumentBuilder { + private static final Logger LOG = LoggerFactory.getLogger( SpdxV3DocumentBuilder.class ); + protected CreationInfo creationInfo; protected Sbom sbom; protected SpdxDocument spdxDoc; + protected SpdxPackage projectPackage; protected SpdxV3LicenseManager licenseManager; + /** + * Holds a mapping of IDs to URIs for any custom licenses defined outside the spdxDoc + */ + protected List customIdToUri = new ArrayList<>(); /** * @param mavenProject Maven project @@ -90,6 +125,8 @@ public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, // process the licenses licenseManager = new SpdxV3LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + // TODO: if we want to support external custom licenses, we will need to add dictionary entries + // to the customIdToUri } /** @@ -101,20 +138,360 @@ public SpdxDocument getSpdxDoc() } @Override - public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) + public void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) throws SpdxBuilderException { - // TODO Auto-generated method stub + try + { + // document comment + if ( projectInformation.getDocumentComment() != null && !projectInformation.getDocumentComment().isEmpty() ) + { + spdxDoc.setComment( projectInformation.getDocumentComment() ); + } + // creator + fillCreatorInfo( projectInformation ); + // data license + // TODO: Add a data license option to the project configuration options + // spdxDoc.setDataLicense( dataLicense ); + // annotations + if ( projectInformation.getDocumentAnnotations() != null && projectInformation.getDocumentAnnotations().length > 0 ) + { + addSpdxAnnotations( projectInformation.getDocumentAnnotations(), spdxDoc ); + } + spdxDoc.setName( projectInformation.getName() ); // Same as package name + // Package level information + projectPackage = createSpdxPackage( projectInformation ); + sbom.getRootElements().add( projectPackage ); + } + catch ( InvalidSPDXAnalysisException | MojoExecutionException e ) + { + throw new SpdxBuilderException( "Error adding package information to SPDX document", e ); + } + } + + /** + * Adds annotation to the element + * @param annotations Annotations to add + * @param element Elements to add the annotations to + * @throws MojoExecutionException On any SPDX parsing errors (typically due to invalid annotation data) + */ + private void addSpdxAnnotations( org.spdx.maven.Annotation[] annotations, Element element ) throws MojoExecutionException + { + for ( org.spdx.maven.Annotation annotation: annotations ) + { + + AnnotationType annotationType = AnnotationType.OTHER; + try + { + annotationType = Spdx2to3Converter.ANNOTATION_TYPE_MAP.get( + org.spdx.library.model.v2.enumerations.AnnotationType + .valueOf( annotation.getAnnotationType() ) ); + } + catch ( Exception ex ) + { + throw new MojoExecutionException( "Invalid annotation type "+annotation.getAnnotationType() ); + } + try + { + CreationInfo creationInfo = new CreationInfo.CreationInfoBuilder( spdxDoc.getModelStore(), + spdxDoc.getModelStore().getNextId(IdType.Anonymous), + spdxDoc.getCopyManager() ) + .setCreated( annotation.getAnnotationDate() ) + .setSpecVersion( SpdxConstantsV3.MODEL_SPEC_VERSION ) + .build(); + creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( annotation.getAnnotator(), creationInfo ) ); + element.createAnnotation( element.getIdPrefix() + element.getModelStore().getNextId( IdType.SpdxId ) ) + .setAnnotationType( annotationType ) + .setStatement( annotation.getAnnotationComment() ) + .setSubject( element ) + .setCreationInfo( creationInfo ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error creating annotation.", e ); + } + } + } + + /** + * Fill in the creator information to the SPDX document + * + * @param projectInformation project level information including the creators + * @throws InvalidSPDXAnalysisException + */ + private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws InvalidSPDXAnalysisException + { + CreationInfo creationInfo = spdxDoc.getCreationInfo(); + String[] parameterCreators = projectInformation.getCreators(); + for ( String parameterCreator : parameterCreators ) + { + try + { + creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( parameterCreator, creationInfo ) ); + } + catch (InvalidSPDXAnalysisException e) + { + LOG.warn( + "Invalid creator string, " + parameterCreator + " will be skipped." ); + } + + } + String comment = projectInformation.getCreatorComment(); + if ( Objects.nonNull( comment ) && !comment.isBlank() ) + { + creationInfo.setComment( comment ); + } + } + + private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation ) throws SpdxBuilderException + { + String copyrightText = projectInformation.getCopyrightText(); + if ( copyrightText == null ) + { + copyrightText = UNSPECIFIED; + } + String downloadUrl = projectInformation.getDownloadUrl(); + + if ( downloadUrl == null || downloadUrl.isBlank() ) + { + downloadUrl = UNSPECIFIED; + } + SpdxPackage pkg; + try + { + + final AnyLicenseInfo concludedLicense = LicenseInfoFactory + .parseSPDXLicenseString( projectInformation.getConcludedLicense(), spdxDoc.getModelStore(), + spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ); + final AnyLicenseInfo declaredLicense = LicenseInfoFactory + .parseSPDXLicenseString( projectInformation.getDeclaredLicense(), spdxDoc.getModelStore(), + spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ); + final Packaging packaging = Packaging.valueOfPackaging( project.getPackaging() ); + final SoftwarePurpose primaryPurpose = packaging != null ? packaging.getSoftwarePurpose() : SoftwarePurpose.LIBRARY; + pkg = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( projectInformation.getName() ) + .setDownloadLocation( downloadUrl ) + .setPrimaryPurpose( primaryPurpose ) + .setCopyrightText( copyrightText ) + .addAllExternalIdentifier( SpdxExternalIdBuilder.getDefaultExternalIdentifiers( spdxDoc, generatePurls, project ) ) + .build(); + pkg.createRelationship( pkg.getIdPrefix() + pkg.getModelStore().getNextId( IdType.SpdxId ) ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( pkg ) + .addTo( declaredLicense ) + .build(); + + pkg.createRelationship( pkg.getIdPrefix() + pkg.getModelStore().getNextId( IdType.SpdxId ) ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( pkg ) + .addTo( concludedLicense ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error creating initial package", e ); + } + // Annotations + if ( projectInformation.getPackageAnnotations() != null && projectInformation.getPackageAnnotations().length > 0 ) + { + try + { + addSpdxAnnotations( projectInformation.getPackageAnnotations(), pkg ); + } + catch ( MojoExecutionException e ) + { + throw new SpdxBuilderException( "Error adding package annotations to SPDX document", e ); + } + } + try + { + // description + if ( projectInformation.getDescription() != null ) + { + pkg.setDescription( projectInformation.getDescription() ); + } + // download url + if ( projectInformation.getDownloadUrl() != null ) + { + pkg.setDownloadLocation( projectInformation.getDownloadUrl() ); + } + // archive file name + if ( projectInformation.getPackageArchiveFileName() != null ) + { + SpdxFile packageFile = pkg.createSpdxFile( pkg.getIdPrefix() + pkg.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( projectInformation.getPackageArchiveFileName() ) + .build(); + + if ( projectInformation.getChecksums() != null ) + { + try + { + for ( Checksum checksum : projectInformation.getChecksums() ) + { + final HashAlgorithm algorithm = Spdx2to3Converter.HASH_ALGORITH_MAP.get( ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ) ); + if ( Objects.isNull( algorithm )) + { + LOG.error( String.format( "Invalid checksum algorithm %s", checksum.getAlgorithm() ) ); + } + else + { + packageFile.getVerifiedUsings().add( packageFile.createHash( packageFile.getModelStore().getNextId( IdType.Anonymous ) ) + .setAlgorithm( algorithm ) + .setHashValue( checksum.getValue() ) + .build() ); + } + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( + "Error adding package information to SPDX document - Invalid checksum provided", e ); + } + } + + pkg.createRelationship( pkg.getIdPrefix() + pkg.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( pkg ) + .addTo( packageFile ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setRelationshipType( RelationshipType.HAS_DISTRIBUTION_ARTIFACT ) + .build(); + } + // home page + if ( projectInformation.getHomePage() != null ) + { + try + { + pkg.setHomePage( projectInformation.getHomePage() ); + } + catch( InvalidSPDXAnalysisException ex ) + { + LOG.warn( "Invalid URL in project POM file: "+projectInformation.getHomePage() ); + } + + } + // source information + if ( projectInformation.getSourceInfo() != null ) + { + pkg.setSourceInfo( projectInformation.getSourceInfo() ); + } + // license comment + if ( projectInformation.getLicenseComment() != null ) + { + pkg.setComment( "License: " + projectInformation.getLicenseComment() ); + } + // originator + if ( projectInformation.getOriginator() != null ) + { + pkg.getOriginatedBys().add( Spdx2to3Converter.stringToAgent( projectInformation.getOriginator(), pkg.getCreationInfo() ) ); + } + // short description + if ( projectInformation.getShortDescription() != null ) + { + pkg.setSummary( projectInformation.getShortDescription() ); + } + // supplier + if ( projectInformation.getSupplier() != null ) + { + pkg.setSuppliedBy( Spdx2to3Converter.stringToAgent( projectInformation.getSupplier(), pkg.getCreationInfo() ) ); + } + // version info + if ( projectInformation.getVersionInfo() != null ) + { + pkg.setPackageVersion( projectInformation.getVersionInfo() ); + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error adding package properties", e ); + } + // external references + ExternalReference[] externalRefs = projectInformation.getExternalRefs(); + try + { + addExternalRefs( externalRefs, pkg ); + } + catch ( MojoExecutionException e ) + { + throw new SpdxBuilderException( "Error adding external references to package", e ); + } + + return pkg; + } + + /** + * @param externalRefs ExternalRefs to add + * @param artifact Spdx Artifact to add the ExternalRefs to + * @throws MojoExecutionException On invalid externalRef data + */ + private void addExternalRefs( ExternalReference[] externalRefs, SoftwareArtifact artifact ) throws MojoExecutionException + { + if ( Objects.isNull( externalRefs )) + { + return; + } + for ( ExternalReference externalRef : externalRefs ) + { + ReferenceCategory cat = null; + + try { + cat = ReferenceCategory.valueOf( externalRef.getCategory().replaceAll( "-", "_" ) ); + } + catch ( Exception ex ) + { + throw new MojoExecutionException("External reference category " + externalRef.getCategory() + " is not recognized as a valid, standard category." ); + } + ReferenceType refType = null; + try + { + refType = ListedReferenceTypes.getListedReferenceTypes().getListedReferenceTypeByName( externalRef.getType() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error getting listed reference type for " + externalRef.getType(), e ); + } + if ( refType == null ) + { + throw new MojoExecutionException( "Listed reference type not found for " + externalRef.getType() ); + } + try + { + Spdx2to3Converter.addExternalRefToArtifact( cat, refType, externalRef.getLocator(), artifact, artifact.getModelStore() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new MojoExecutionException( "Error adding external ref to artifact", e ); + } + } } @Override public void collectSpdxFileInformation( List sources, String baseDir, SpdxDefaultFileInformation defaultFileInformation, HashMap pathSpecificInformation, - Set checksumAlgorithms ) + Set checksumAlgorithms ) throws SpdxBuilderException { - // TODO Auto-generated method stub - + SpdxV3FileCollector fileCollector = new SpdxV3FileCollector( customIdToUri ); + try + { + fileCollector.collectFiles( sources, baseDir, defaultFileInformation, + pathSpecificInformation, projectPackage, RelationshipType.GENERATES, spdxDoc, checksumAlgorithms ); + Relationship pkgRelationship = projectPackage.createRelationship( projectPackage.getIdPrefix() + projectPackage.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( projectPackage ) + .setRelationshipType( RelationshipType.CONTAINS ) + .build(); + for ( SpdxFile file : fileCollector.getFiles() ) + { + pkgRelationship.getTos().add( file ); + } + } + catch ( SpdxCollectionException|InvalidSPDXAnalysisException e ) + { + throw new SpdxBuilderException( "Error collecting SPDX file information", e ); + } + // TODO: Set a GITOID identifier } @Override @@ -161,21 +538,13 @@ public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) t @Override public CoreModelObject getProjectPackage() { - // TODO Auto-generated method stub - return null; - } - - public CoreModelObject convertChecksum( String algorithm, String checksum ) - { - // TODO Auto-generated method stub - return null; + return projectPackage; } @Override - public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) + public String mavenLicenseListToSpdxLicenseExpression( List mavenLicenses ) throws LicenseManagerException { - // TODO Auto-generated method stub - return null; + return licenseManager.mavenLicenseListToSpdxLicense( mavenLicenses ).toString(); } /** diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java new file mode 100644 index 0000000..5eebefe --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java @@ -0,0 +1,500 @@ +/* + * Copyright 2014 Source Auditor Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.spdx.maven.utils; + +import java.io.File; +import java.util.*; +import java.util.Map.Entry; + +import org.apache.maven.shared.model.fileset.FileSet; +import org.apache.maven.shared.model.fileset.util.FileSetManager; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.conversion.Spdx2to3Converter; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.FileType; +import org.spdx.library.model.v3_0_1.core.Agent; +import org.spdx.library.model.v3_0_1.core.DictionaryEntry; +import org.spdx.library.model.v3_0_1.core.HashAlgorithm; +import org.spdx.library.model.v3_0_1.core.IntegrityMethod; +import org.spdx.library.model.v3_0_1.core.PositiveIntegerRange; +import org.spdx.library.model.v3_0_1.core.RelationshipCompleteness; +import org.spdx.library.model.v3_0_1.core.RelationshipType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.library.model.v3_0_1.software.Snippet; +import org.spdx.library.model.v3_0_1.software.SoftwarePurpose; +import org.spdx.library.model.v3_0_1.software.SpdxFile; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.maven.Checksum; +import org.spdx.maven.SnippetInfo; +import org.spdx.storage.IModelStore.IdType; + + +/** + * Collects SPDX file information from directories in SPDX Spec version 3 format + *

+ * The method collectFilesInDirectory(FileSet[] filesets) will scan and create SPDX File information for + * all files in the filesets. + * + * @author Gary O'Neall + */ +public class SpdxV3FileCollector extends AbstractFileCollector +{ + static final Map EXT_TO_MEDIA_TYPE = new HashMap<>(); + static final Map EXT_TO_PURPOSE = new HashMap<>(); + + static + { + for ( Entry entry : SpdxV2FileCollector.EXT_TO_FILE_TYPE.entrySet() ) + { + switch ( entry.getValue() ) + { + case SOURCE: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "text/plain" ); + EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.SOURCE ); + break; + case BINARY: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "application/octet-stream" ); + EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.LIBRARY ); + break; + case ARCHIVE: EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.ARCHIVE ); break; + case APPLICATION: EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.APPLICATION ); break; + case AUDIO: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "audio/*" ); break; + case IMAGE: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "image/*" ); break; + case TEXT: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "text/plain" ); break; + case VIDEO: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "video/*" ); break; + case DOCUMENTATION: EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.DOCUMENTATION ); break; + case SPDX: EXT_TO_MEDIA_TYPE.put( entry.getKey(), "application/spdx" ); + EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.BOM ); break; + case OTHER: EXT_TO_PURPOSE.put( entry.getKey(), SoftwarePurpose.OTHER ); break; + } + } + } + + /** + * Map of fileName, SPDXFile for all files in the SPDX document + */ + Map spdxFiles = new HashMap<>(); + List spdxSnippets = new ArrayList<>(); + + FileSetManager fileSetManager = new FileSetManager(); + + private List customIdToUri; + + /** + * SpdxFileCollector collects SPDX file information for files + * @param customIdToUri Holds a mapping of IDs to URIs for any custom licenses defined outside the spdxDoc + */ + public SpdxV3FileCollector( List customIdToUri) + { + this.customIdToUri = customIdToUri; + } + + + /** + * Collect file information in the directory (including subdirectories). + * + * @param fileSets FileSets containing the description of the directory to be scanned + * @param baseDir project base directory used to construct the relative paths for the SPDX files + * @param defaultFileInformation Information on default SPDX field data for the files + * @param pathSpecificInformation Map of path to file information used to override the default file information + * @param relationshipType Type of relationship to the project package + * @param projectPackage Package to which the files belong + * @param spdxDoc SPDX document which contains the extracted license infos that may be needed for license parsing + * + * @throws SpdxCollectionException + */ + public void collectFiles( List fileSets, String baseDir, + SpdxDefaultFileInformation defaultFileInformation, + Map pathSpecificInformation, + SpdxPackage projectPackage, RelationshipType relationshipType, + SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException + { + for ( FileSet fileSet : fileSets ) + { + String[] includedFiles = fileSetManager.getIncludedFiles( fileSet ); + for ( String includedFile : includedFiles ) + { + String filePath = fileSet.getDirectory() + File.separator + includedFile; + File file = new File( filePath ); + String relativeFilePath = file.getAbsolutePath().substring( baseDir.length() + 1 ).replace( '\\', '/' ); + SpdxDefaultFileInformation fileInfo = findDefaultFileInformation( relativeFilePath, + pathSpecificInformation ); + if ( fileInfo == null ) + { + fileInfo = defaultFileInformation; + } + + String outputFileName; + if ( fileSet.getOutputDirectory() != null ) + { + outputFileName = fileSet.getOutputDirectory() + File.separator + includedFile; + } + else + { + outputFileName = file.getAbsolutePath().substring( baseDir.length() + 1 ); + } + collectFile( file, outputFileName, fileInfo, relationshipType, projectPackage, spdxDoc, algorithms ); + } + } + } + + /** + * Find the most appropriate file information based on the lowest level match (closed to file) + * + * @param filePath + * @param pathSpecificInformation + * @return + */ + private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, Map pathSpecificInformation ) + { + LOG.debug( "Checking for file path " + filePath ); + SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); + if ( retval != null ) + { + LOG.debug( "Found filepath" ); + return retval; + } + // see if any of the parent directories contain default information which should be used + String parentPath = filePath; + int parentPathIndex = 0; + do + { + parentPathIndex = parentPath.lastIndexOf( "/" ); + if ( parentPathIndex > 0 ) + { + parentPath = parentPath.substring( 0, parentPathIndex ); + retval = pathSpecificInformation.get( parentPath ); + } + } while ( retval == null && parentPathIndex > 0 ); + if ( retval != null ) + { + LOG.debug( "Found directory containing file path for path specific information. File path: " + parentPath ); + } + return retval; + } + + /** + * Collect SPDX information for a specific file + * + * @param file + * @param outputFileName Path to the output file name relative to the root of the output archive file + * @param relationshipType Type of relationship to the project package + * @param projectPackage Package to which the files belong + * @param spdxDoc SPDX Document which will contain the files + * @param algorithms algorithms to use to generate checksums + * @throws SpdxCollectionException + */ + private void collectFile( File file, String outputFileName, SpdxDefaultFileInformation fileInfo, + RelationshipType relationshipType, SpdxPackage projectPackage, + SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException + { + if ( spdxFiles.containsKey( file.getPath() ) ) + { + return; // already added from a previous scan + } + SpdxFile spdxFile = convertToSpdxFile( file, outputFileName, fileInfo, algorithms, spdxDoc ); + try + { + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setFrom( spdxFile ) + .addTo( projectPackage ) + .setRelationshipType( relationshipType ) + .build(); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file relationship", e ); + } + if ( fileInfo.getSnippets() != null ) + { + for ( SnippetInfo snippet : fileInfo.getSnippets() ) + { + Snippet spdxSnippet; + try + { + spdxSnippet = convertToSpdxSnippet( snippet, spdxFile ); + } + catch ( SpdxBuilderException e ) + { + throw new SpdxCollectionException( "Error creating SPDX snippet information.", e ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( + "Error processing SPDX snippet information.", + e ); + } + spdxSnippets.add( spdxSnippet ); + } + } + spdxFiles.put( file.getPath(), spdxFile ); + } + + /** + * Create an SpdxSnippet from the snippet information provided + * @param snippet Information on the Snippet + * @param spdxFile File containing the snippet + * @return SPDX Snippet + * @throws SpdxBuilderException on Maven metadata related errors + * @throws InvalidSPDXAnalysisException on SPDX analysis errors + */ + private Snippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile ) throws SpdxBuilderException, InvalidSPDXAnalysisException + { + //TODO: Add annotations to snippet + + PositiveIntegerRange byteRange = spdxFile.createPositiveIntegerRange( spdxFile.getModelStore().getNextId( IdType.Anonymous ) ) + .setBeginIntegerRange( snippet.getByteRangeStart() ) + .setEndIntegerRange( snippet.getByteRangeEnd() ) + .build(); + PositiveIntegerRange lineRange = spdxFile.createPositiveIntegerRange( spdxFile.getModelStore().getNextId( IdType.Anonymous ) ) + .setBeginIntegerRange( snippet.getLineRangeStart() ) + .setEndIntegerRange( snippet.getLineRangeEnd() ) + .build(); + + Snippet retval = spdxFile.createSnippet( spdxFile.getIdPrefix() + spdxFile.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( snippet.getName() ) + .setCopyrightText( snippet.getCopyrightText() ) + .setSnippetFromFile( spdxFile ) + .setByteRange( byteRange ) + .setLineRange( lineRange ) + .build(); + + String comment = snippet.getComment(); + if ( Objects.isNull( comment ) ) + { + comment = ""; + } + String licenseComment = snippet.getLicensComment(); + if ( Objects.nonNull( licenseComment ) && !licenseComment.isBlank() ) + { + comment = comment + "; License: " + licenseComment; + } + retval.setComment( comment ); + final AnyLicenseInfo concludedLicense = LicenseInfoFactory + .parseSPDXLicenseString( snippet.getConcludedLicense(), spdxFile.getModelStore(), + spdxFile.getIdPrefix(), spdxFile.getCopyManager(), customIdToUri ); + retval.createRelationship( retval.getIdPrefix() + retval.getModelStore().getNextId( IdType.SpdxId ) ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( retval ) + .addTo( concludedLicense ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ); + + final AnyLicenseInfo declaredLicense = LicenseInfoFactory + .parseSPDXLicenseString( snippet.getLicenseInfoInSnippet(), spdxFile.getModelStore(), + spdxFile.getIdPrefix(), spdxFile.getCopyManager(), customIdToUri ); + retval.createRelationship( retval.getIdPrefix() + retval.getModelStore().getNextId( IdType.SpdxId ) ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( retval ) + .addTo( declaredLicense ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ); + return retval; + } + + /** + * @param file + * @param outputFileName Path to the output file name relative to the root of the output archive file + * @param defaultFileInformation Information on default SPDX field data for the files + * @param algorithms algorithms to use to generate checksums + * @param spdxDoc SPDX document which will contain the SPDX file + * @return + * @throws SpdxCollectionException + */ + private SpdxFile convertToSpdxFile( File file, String outputFileName, + SpdxDefaultFileInformation defaultFileInformation, + Set algorithms, + SpdxDocument spdxDoc ) throws SpdxCollectionException + { + String relativePath = convertFilePathToSpdxFileName( outputFileName ); + String extension = getExtension( file ).trim().toUpperCase(); + SoftwarePurpose purpose = EXT_TO_PURPOSE.getOrDefault( extension, SoftwarePurpose.OTHER ); + Collection hashes = new ArrayList<>(); + try + { + Set checksums = generateChecksum( file, algorithms ); + for ( Checksum checksum : checksums ) + { + final HashAlgorithm algorithm = Spdx2to3Converter.HASH_ALGORITH_MAP.get( ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ) ); + if ( Objects.isNull( algorithm ) ) + { + throw new SpdxCollectionException( "Invalid checksum algorithm for file "+file.getName() ); + } + hashes.add( spdxDoc.createHash( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .setAlgorithm( algorithm ) + .setHashValue( checksum.getValue() ) + .build() ); + } + + } + catch ( SpdxCollectionException | InvalidSPDXAnalysisException e1 ) + { + throw new SpdxCollectionException( "Unable to generate checksum for file "+file.getName() ); + } + AnyLicenseInfo concludedLicense = null; + AnyLicenseInfo license = null; + String licenseComment = defaultFileInformation.getLicenseComment(); + if ( SoftwarePurpose.SOURCE.equals( purpose ) && file.length() < SpdxSourceFileParser.MAXIMUM_SOURCE_FILE_LENGTH ) + { + List fileSpdxLicenses = null; + try + { + fileSpdxLicenses = SpdxSourceFileParser.parseFileForSpdxLicenses( file ); + } + catch ( SpdxSourceParserException ex ) + { + LOG.error( "Error parsing for SPDX license ID's", ex ); + } + if ( fileSpdxLicenses != null && fileSpdxLicenses.size() > 0 ) + { + // The file has declared licenses of the form SPDX-License-Identifier: licenseId + try + { + if ( fileSpdxLicenses.size() == 1 ) + { + license = LicenseInfoFactory.parseSPDXLicenseString( fileSpdxLicenses.get( 0 ) ); + } + else + { + Set licenseSet = new HashSet<>(); + for ( String licenseExpression : fileSpdxLicenses ) + { + licenseSet.add( LicenseInfoFactory.parseSPDXLicenseString( licenseExpression ) ); + } + license = spdxDoc.createConjunctiveLicenseSet( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .addAllMember( licenseSet ) + .build(); + } + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file - unable to create a license set", e ); + } + if ( licenseComment == null ) + { + licenseComment = ""; + } + else if ( licenseComment.length() > 0 ) + { + licenseComment = licenseComment.concat( "; " ); + } + licenseComment = licenseComment.concat( "This file contains SPDX-License-Identifiers for " ); + licenseComment = licenseComment.concat( license.toString() ); + } + } + if ( license == null ) + { + try + { + license = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getDeclaredLicense() ); + concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getConcludedLicense() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file - unable create default file license", e ); + } + } + else + { + concludedLicense = license; + } + + String copyright = defaultFileInformation.getCopyright(); + String notice = defaultFileInformation.getNotice(); + String comment = defaultFileInformation.getComment(); + if ( Objects.isNull( comment ) ) + { + comment = ""; + } + if ( Objects.nonNull( licenseComment ) && !licenseComment.isBlank() ) + { + comment = comment + " ;License: " + licenseComment; + } + String[] defaultContributors = defaultFileInformation.getContributors(); + List contributors = new ArrayList<>(); + if ( defaultContributors != null ) { + for ( String contributor : defaultFileInformation.getContributors() ) + { + if ( Objects.nonNull( contributor ) && !contributor.isBlank() ) + { + try + { + contributors.add( spdxDoc.createPerson( spdxDoc.getModelStore().getNextId( IdType.Anonymous ) ) + .setName( contributor ) + .setDescription( "Contributor" ) + .build() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + LOG.warn( "Error creating contributor "+contributor+" for file "+file+". Skipping." ); + } + } + } + } else { + contributors = new ArrayList<>(); + } + + SpdxFile retval = null; + //TODO: Add annotation + try + { + retval = spdxDoc.createSpdxFile( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( relativePath ) + .setCopyrightText( copyright ) + .setComment( comment ) + .setPrimaryPurpose( purpose ) + .addAllVerifiedUsing( hashes ) + .addAttributionText( notice ) + .addAllOriginatedBy( contributors ) + .build(); + String mediaType = EXT_TO_MEDIA_TYPE.get( extension ); + if ( Objects.nonNull( mediaType ) ) + { + retval.setContentType( mediaType ); + } + retval.createRelationship( retval.getIdPrefix() + retval.getModelStore().getNextId( IdType.SpdxId ) ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( retval ) + .addTo( concludedLicense ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ); + retval.createRelationship( retval.getIdPrefix() + retval.getModelStore().getNextId( IdType.SpdxId ) ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( retval ) + .addTo( concludedLicense ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ); + } + catch ( InvalidSPDXAnalysisException e ) + { + throw new SpdxCollectionException( "Error creating SPDX file", e ); + } + + return retval; + } + + /** + * @return SPDX Files which have been acquired through the collectFilesInDirectory method + */ + public Collection getFiles() + { + return spdxFiles.values(); + } + + /** + * @return SPDX Snippets collected through the collectFilesInDirectory method + */ + public List getSnippets() + { + return this.spdxSnippets; + } +} From 530724b54c4837d5056da8204c5e7ac0c67b448c Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Tue, 12 Nov 2024 16:58:43 -0800 Subject: [PATCH 04/10] Intermediate checkin - unit tests pass --- pom.xml | 2 +- src/main/java/org/spdx/maven/Checksum.java | 18 + .../java/org/spdx/maven/CreateSpdxMojo.java | 6 + .../maven/utils/AbstractFileCollector.java | 2 +- .../maven/utils/SpdxV2DocumentBuilder.java | 2 +- .../spdx/maven/utils/SpdxV2FileCollector.java | 2 +- .../maven/utils/SpdxV3DocumentBuilder.java | 10 +- .../spdx/maven/utils/SpdxV3FileCollector.java | 16 +- .../maven/utils/SpdxV3LicenseManager.java | 2 +- ...{TestSpdxMojo.java => TestSpdxV2Mojo.java} | 173 +++-- ...jo.java => TestWithSessionSpdxV2Mojo.java} | 36 +- .../utils/TestMavenToSpdxLicenseMapper.java | 112 ++- .../maven/utils/TestSpdxSourceFileParser.java | 87 +-- ...ctor.java => TestSpdxV2FileCollector.java} | 141 ++-- ...ger.java => TestSpdxV2LicenseManager.java} | 22 +- .../maven/utils/TestSpdxV3FileCollector.java | 665 ++++++++++++++++++ .../maven/utils/TestSpdxV3LicenseManager.java | 319 +++++++++ 17 files changed, 1361 insertions(+), 254 deletions(-) rename src/test/java/org/spdx/maven/{TestSpdxMojo.java => TestSpdxV2Mojo.java} (89%) rename src/test/java/org/spdx/maven/{TestWithSessionSpdxMojo.java => TestWithSessionSpdxV2Mojo.java} (87%) rename src/test/java/org/spdx/maven/utils/{TestSpdxFileCollector.java => TestSpdxV2FileCollector.java} (85%) rename src/test/java/org/spdx/maven/utils/{TestLicenseManager.java => TestSpdxV2LicenseManager.java} (94%) create mode 100644 src/test/java/org/spdx/maven/utils/TestSpdxV3FileCollector.java create mode 100644 src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java diff --git a/pom.xml b/pom.xml index 4afbf6f..12ae396 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ org.spdx spdx-rdf-store - 2.0.0-Alpha + 2.0.1-SNAPSHOT org.spdx diff --git a/src/main/java/org/spdx/maven/Checksum.java b/src/main/java/org/spdx/maven/Checksum.java index 63e794a..d86bba1 100644 --- a/src/main/java/org/spdx/maven/Checksum.java +++ b/src/main/java/org/spdx/maven/Checksum.java @@ -4,6 +4,8 @@ */ package org.spdx.maven; +import java.util.Objects; + /** * Holds the value and algorithm of a checksum used in the SPDX document * @@ -58,6 +60,22 @@ public void setAlgorithm( String algorithm ) this.algorithm = algorithm; } + @Override + public boolean equals(Object o) + { + if ( !( o instanceof Checksum ) ) + { + return false; + } + Checksum compare = (Checksum)o; + return Objects.equals( compare.getAlgorithm(), this.getAlgorithm() ) && + Objects.equals( compare.getValue(), this.getValue() ); + } + @Override + public int hashCode() + { + return ( Objects.isNull( algorithm ) ? 11 : algorithm.hashCode() ) ^ ( Objects.isNull( value ) ? 17 : value.hashCode() ); + } } diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index 02ffab1..7974f25 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -39,6 +39,7 @@ import org.apache.maven.shared.model.fileset.FileSet; import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.core.SpdxCoreConstants.SpdxMajorVersion; +import org.spdx.library.SpdxModelFactory; import org.spdx.maven.utils.LicenseMapperException; import org.spdx.maven.utils.SpdxBuilderException; import org.spdx.maven.utils.SpdxCollectionException; @@ -107,6 +108,11 @@ public class CreateSpdxMojo extends AbstractMojo public static final String JSON_OUTPUT_FORMAT = "JSON"; public static final String RDF_OUTPUT_FORMAT = "RDF/XML"; + + static + { + SpdxModelFactory.init(); + } @Component private MavenProject mavenProject; diff --git a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java index 725f3e7..5393255 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java +++ b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java @@ -155,7 +155,7 @@ public String convertFilePathToSpdxFileName( String filePath ) return result; } - protected FileType extensionToFileType( String fileExtension ) + protected static FileType extensionToFileType( String fileExtension ) { return EXT_TO_FILE_TYPE.getOrDefault( fileExtension.trim().toUpperCase(), FileType.OTHER ); diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java index 1f93cef..2b754f1 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -96,7 +96,7 @@ public SpdxV2DocumentBuilder( MavenProject mavenProject, boolean generatePurls, // create the SPDX document try { - modelStore = outputFormatEnum == OutputFormat.RDF_XML ? new RdfStore() : new MultiFormatStore( new InMemSpdxStore(), Format.JSON_PRETTY ); + modelStore = outputFormatEnum == OutputFormat.RDF_XML ? new RdfStore( spdxDocumentNamespace.toString() ) : new MultiFormatStore( new InMemSpdxStore(), Format.JSON_PRETTY ); copyManager = new ModelCopyManager(); spdxDoc = SpdxModelFactoryCompatV2.createSpdxDocumentV2( modelStore, spdxDocumentNamespace.toString(), copyManager ); } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java index f3af478..030b67b 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -311,7 +311,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, } catch ( InvalidSPDXAnalysisException e ) { - throw new SpdxCollectionException( "Error creating SPDX file - unable to create a license set", e ); + LOG.error( "Invalid license expressions found in source file "+file.getName(), e ); } if ( licenseComment == null ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index cb4fffc..9778730 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -284,11 +284,11 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation .build(); pkg.createRelationship( pkg.getIdPrefix() + pkg.getModelStore().getNextId( IdType.SpdxId ) ) - .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) - .setCompleteness( RelationshipCompleteness.COMPLETE ) - .setFrom( pkg ) - .addTo( concludedLicense ) - .build(); + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .setCompleteness( RelationshipCompleteness.COMPLETE ) + .setFrom( pkg ) + .addTo( concludedLicense ) + .build(); } catch ( InvalidSPDXAnalysisException e ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java index 5eebefe..faa3062 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java @@ -290,7 +290,8 @@ private Snippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile ) t .setCompleteness( RelationshipCompleteness.COMPLETE ) .setFrom( retval ) .addTo( concludedLicense ) - .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ); + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .build(); final AnyLicenseInfo declaredLicense = LicenseInfoFactory .parseSPDXLicenseString( snippet.getLicenseInfoInSnippet(), spdxFile.getModelStore(), @@ -299,7 +300,8 @@ private Snippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile ) t .setCompleteness( RelationshipCompleteness.COMPLETE ) .setFrom( retval ) .addTo( declaredLicense ) - .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ); + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .build(); return retval; } @@ -379,7 +381,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, } catch ( InvalidSPDXAnalysisException e ) { - throw new SpdxCollectionException( "Error creating SPDX file - unable to create a license set", e ); + LOG.error( "Invalid license expressions found in source file "+file.getName(), e ); } if ( licenseComment == null ) { @@ -467,12 +469,14 @@ else if ( licenseComment.length() > 0 ) .setCompleteness( RelationshipCompleteness.COMPLETE ) .setFrom( retval ) .addTo( concludedLicense ) - .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ); + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .build(); retval.createRelationship( retval.getIdPrefix() + retval.getModelStore().getNextId( IdType.SpdxId ) ) .setCompleteness( RelationshipCompleteness.COMPLETE ) .setFrom( retval ) - .addTo( concludedLicense ) - .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ); + .addTo( license ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .build(); } catch ( InvalidSPDXAnalysisException e ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java index a6fbbca..870ad11 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java @@ -100,7 +100,7 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana CustomLicense spdxLicense; try { - spdxLicense = spdxDoc.createCustomLicense( spdxDoc.getIdPrefix() + "/" + license.getLicenseId() ) + spdxLicense = spdxDoc.createCustomLicense( spdxDoc.getIdPrefix() + license.getLicenseId() ) .setLicenseText( license.getExtractedText() ) .setName( license.getName() ) .setComment( license.getComment() ) diff --git a/src/test/java/org/spdx/maven/TestSpdxMojo.java b/src/test/java/org/spdx/maven/TestSpdxV2Mojo.java similarity index 89% rename from src/test/java/org/spdx/maven/TestSpdxMojo.java rename to src/test/java/org/spdx/maven/TestSpdxV2Mojo.java index d97db6d..89a950c 100644 --- a/src/test/java/org/spdx/maven/TestSpdxMojo.java +++ b/src/test/java/org/spdx/maven/TestSpdxV2Mojo.java @@ -15,28 +15,30 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; +import org.spdx.core.DefaultModelStore; import org.spdx.jacksonstore.MultiFormatStore; import org.spdx.jacksonstore.MultiFormatStore.Format; +import org.spdx.library.LicenseInfoFactory; import org.spdx.library.ModelCopyManager; -import org.spdx.library.model.ExternalRef; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxElement; -import org.spdx.library.model.SpdxFile; -import org.spdx.library.model.SpdxModelFactory; -import org.spdx.library.model.SpdxPackage; -import org.spdx.library.model.SpdxSnippet; -import org.spdx.library.model.enumerations.AnnotationType; -import org.spdx.library.model.enumerations.ReferenceCategory; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.ExtractedLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.ExternalRef; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxElement; +import org.spdx.library.model.v2.SpdxFile; +import org.spdx.library.model.v2.SpdxPackage; +import org.spdx.library.model.v2.SpdxSnippet; +import org.spdx.library.model.v2.enumerations.AnnotationType; +import org.spdx.library.model.v2.enumerations.ReferenceCategory; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.ExtractedLicenseInfo; import org.spdx.library.referencetype.ListedReferenceTypes; -import org.spdx.maven.utils.TestSpdxFileCollector; +import org.spdx.maven.utils.TestSpdxV2FileCollector; import org.spdx.spdxRdfStore.RdfStore; import org.spdx.storage.ISerializableModelStore; import org.spdx.storage.simple.InMemSpdxStore; -public class TestSpdxMojo extends AbstractMojoTestCase +public class TestSpdxV2Mojo extends AbstractMojoTestCase { private static final String UNIT_TEST_RESOURCE_DIR = "target/test-classes/unit/spdx-maven-plugin-test"; @@ -55,6 +57,8 @@ public static void tearDownAfterClass() throws Exception protected void setUp() throws Exception { super.setUp(); + SpdxModelFactory.init(); + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); } @After @@ -82,11 +86,9 @@ public void testExecute() throws Exception ISerializableModelStore modelStore = new RdfStore(); ModelCopyManager copyManager = new ModelCopyManager(); SpdxDocument result; - String documentUri; try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + result = (SpdxDocument)modelStore.deSerialize( is, false ); } List warnings = result.verify(); assertEquals( 0, warnings.size() ); @@ -140,9 +142,9 @@ else if ( seeAlso.equals( "http://www.test.url/testLicense2-alt.html" ) ) assertEquals( "Document Comment", result.getComment().get() ); // documentAnnotations assertEquals( 2, result.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation1 = null; - org.spdx.library.model.Annotation annotation2 = null; - for ( org.spdx.library.model.Annotation annotation : result.getAnnotations() ) + org.spdx.library.model.v2.Annotation annotation1 = null; + org.spdx.library.model.v2.Annotation annotation2 = null; + for ( org.spdx.library.model.v2.Annotation annotation : result.getAnnotations() ) { if ( annotation.getComment().equals( "Annotation1" ) ) { @@ -188,16 +190,16 @@ else if ( creator.equals( "Person: Creator2" ) ) SpdxPackage pkg = (SpdxPackage) described; // packageAnnotations assertEquals( 1, pkg.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.Annotation [pkg.getAnnotations().size()] )[0]; + org.spdx.library.model.v2.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.v2.Annotation [pkg.getAnnotations().size()] )[0]; assertEquals( "PackageAnnotation", annotation.getComment() ); assertEquals( "2015-01-29T18:30:22Z", annotation.getAnnotationDate() ); assertEquals( "Person:Test Package Person", annotation.getAnnotator() ); assertEquals( AnnotationType.REVIEW, annotation.getAnnotationType() ); //licenseDeclared - AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseById( "BSD-2-Clause" ); + AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-2-Clause" ); assertEquals( licenseDeclared, pkg.getLicenseDeclared() ); //licenseConcluded - AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseById( "BSD-3-Clause" ); + AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-3-Clause" ); assertEquals( licenseConcluded, pkg.getLicenseConcluded() ); //licenseComments assertEquals( "License comments", pkg.getLicenseComments().get() ); @@ -277,7 +279,8 @@ else if ( externalRefs[0].getReferenceCategory().equals( } assertEquals( 0, filePaths.size() ); List snippets = new ArrayList<>(); - SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxSnippet.class ).forEach( (snippet) -> { + SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsCompatV2.CLASS_SPDX_SNIPPET, + null, result.getIdPrefix() ).forEach( (snippet) -> { snippets.add( (SpdxSnippet)snippet ); }); assertEquals( 2, snippets.size() ); @@ -287,10 +290,10 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet License Comment", snippets.get( 0 ).getLicenseComments().get() ); assertEquals( "SnippetName", snippets.get( 0 ).getName().get() ); assertEquals( "1231:3442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); assertEquals( "BSD-2-Clause", snippets.get( 0 ).getLicenseConcluded().toString() ); assertEquals( "BSD-2-Clause-FreeBSD", snippets.get( 0 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 0 ).getLicenseInfoFromFiles().size()] )[0].toString() ); - assertEquals( "44:55", TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); + assertEquals( "44:55", TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 0 ).getSnippetFromFile().getId() ); assertEquals( "Snippet Comment2", snippets.get( 1 ).getComment().get() ); @@ -298,11 +301,11 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet2 License Comment", snippets.get( 1 ).getLicenseComments().get() ); assertEquals( "SnippetName2", snippets.get( 1 ).getName().get() ); assertEquals( "31231:33442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); assertEquals( "MITNFA", snippets.get( 1 ).getLicenseConcluded().toString() ); assertEquals( "LicenseRef-testLicense", snippets.get( 1 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 1 ).getLicenseInfoFromFiles().size()] )[0].toString() ); assertEquals( "444:554", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 1 ).getSnippetFromFile().getId() ); //TODO Test dependencies } @@ -326,11 +329,9 @@ public void testExecuteUseArtfactId() throws Exception ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); ModelCopyManager copyManager = new ModelCopyManager(); SpdxDocument result; - String documentUri; try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + result = (SpdxDocument)modelStore.deSerialize( is, false ); } List warnings = result.verify(); assertEquals( 0, warnings.size() ); @@ -384,9 +385,9 @@ else if ( seeAlso.equals( "http://www.test.url/testLicense2-alt.html" ) ) assertEquals( "Document Comment", result.getComment().get() ); // documentAnnotations assertEquals( 2, result.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation1 = null; - org.spdx.library.model.Annotation annotation2 = null; - for ( org.spdx.library.model.Annotation annotation : result.getAnnotations() ) + org.spdx.library.model.v2.Annotation annotation1 = null; + org.spdx.library.model.v2.Annotation annotation2 = null; + for ( org.spdx.library.model.v2.Annotation annotation : result.getAnnotations() ) { if ( annotation.getComment().equals( "Annotation1" ) ) { @@ -434,16 +435,16 @@ else if ( creator.equals( "Person: Creator2" ) ) assertEquals( "org.spdx:spdx maven plugin test", pkg.getName().get() ); // packageAnnotations assertEquals( 1, pkg.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.Annotation [pkg.getAnnotations().size()] )[0]; + org.spdx.library.model.v2.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.v2.Annotation [pkg.getAnnotations().size()] )[0]; assertEquals( "PackageAnnotation", annotation.getComment() ); assertEquals( "2015-01-29T18:30:22Z", annotation.getAnnotationDate() ); assertEquals( "Person:Test Package Person", annotation.getAnnotator() ); assertEquals( AnnotationType.REVIEW, annotation.getAnnotationType() ); //licenseDeclared - AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseById( "BSD-2-Clause" ); + AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-2-Clause" ); assertEquals( licenseDeclared, pkg.getLicenseDeclared() ); //licenseConcluded - AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseById( "BSD-3-Clause" ); + AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-3-Clause" ); assertEquals( licenseConcluded, pkg.getLicenseConcluded() ); //licenseComments assertEquals( "License comments", pkg.getLicenseComments().get() ); @@ -523,7 +524,8 @@ else if ( externalRefs[0].getReferenceCategory().equals( } assertEquals( 0, filePaths.size() ); List snippets = new ArrayList<>(); - SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxSnippet.class ).forEach( (snippet) -> { + SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsCompatV2.CLASS_SPDX_SNIPPET, + null, result.getIdPrefix() ).forEach( (snippet) -> { snippets.add( (SpdxSnippet)snippet ); }); assertEquals( 2, snippets.size() ); @@ -533,10 +535,10 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet License Comment", snippets.get( 0 ).getLicenseComments().get() ); assertEquals( "SnippetName", snippets.get( 0 ).getName().get() ); assertEquals( "1231:3442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); assertEquals( "BSD-2-Clause", snippets.get( 0 ).getLicenseConcluded().toString() ); assertEquals( "BSD-2-Clause-FreeBSD", snippets.get( 0 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 0 ).getLicenseInfoFromFiles().size()] )[0].toString() ); - assertEquals( "44:55", TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); + assertEquals( "44:55", TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 0 ).getSnippetFromFile().getId() ); assertEquals( "Snippet Comment2", snippets.get( 1 ).getComment().get() ); @@ -544,11 +546,11 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet2 License Comment", snippets.get( 1 ).getLicenseComments().get() ); assertEquals( "SnippetName2", snippets.get( 1 ).getName().get() ); assertEquals( "31231:33442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); assertEquals( "MITNFA", snippets.get( 1 ).getLicenseConcluded().toString() ); assertEquals( "LicenseRef-testLicense", snippets.get( 1 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 1 ).getLicenseInfoFromFiles().size()] )[0].toString() ); assertEquals( "444:554", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 1 ).getSnippetFromFile().getId() ); //TODO Test dependencies } @@ -572,11 +574,9 @@ public void testExecuteJson() throws Exception ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); ModelCopyManager copyManager = new ModelCopyManager(); SpdxDocument result; - String documentUri; try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + result = (SpdxDocument)modelStore.deSerialize( is, false ); } List warnings = result.verify(); assertEquals( 0, warnings.size() ); @@ -630,9 +630,9 @@ else if ( seeAlso.equals( "http://www.test.url/testLicense2-alt.html" ) ) assertEquals( "Document Comment", result.getComment().get() ); // documentAnnotations assertEquals( 2, result.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation1 = null; - org.spdx.library.model.Annotation annotation2 = null; - for ( org.spdx.library.model.Annotation annotation : result.getAnnotations() ) + org.spdx.library.model.v2.Annotation annotation1 = null; + org.spdx.library.model.v2.Annotation annotation2 = null; + for ( org.spdx.library.model.v2.Annotation annotation : result.getAnnotations() ) { if ( annotation.getComment().equals( "Annotation1" ) ) { @@ -680,16 +680,16 @@ else if ( creator.equals( "Person: Creator2" ) ) assertEquals( "Test SPDX Plugin", pkg.getName().get() ); // packageAnnotations assertEquals( 1, pkg.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.Annotation [pkg.getAnnotations().size()] )[0]; + org.spdx.library.model.v2.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.v2.Annotation [pkg.getAnnotations().size()] )[0]; assertEquals( "PackageAnnotation", annotation.getComment() ); assertEquals( "2015-01-29T18:30:22Z", annotation.getAnnotationDate() ); assertEquals( "Person:Test Package Person", annotation.getAnnotator() ); assertEquals( AnnotationType.REVIEW, annotation.getAnnotationType() ); //licenseDeclared - AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseById( "BSD-2-Clause" ); + AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-2-Clause" ); assertEquals( licenseDeclared, pkg.getLicenseDeclared() ); //licenseConcluded - AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseById( "BSD-3-Clause" ); + AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-3-Clause" ); assertEquals( licenseConcluded, pkg.getLicenseConcluded() ); //licenseComments assertEquals( "License comments", pkg.getLicenseComments().get() ); @@ -769,7 +769,8 @@ else if ( externalRefs[0].getReferenceCategory().equals( } assertEquals( 0, filePaths.size() ); List snippets = new ArrayList<>(); - SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxSnippet.class ).forEach( (snippet) -> { + SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsCompatV2.CLASS_SPDX_SNIPPET, + null, result.getIdPrefix() ).forEach( (snippet) -> { snippets.add( (SpdxSnippet)snippet ); }); assertEquals( 2, snippets.size() ); @@ -779,10 +780,10 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet License Comment", snippets.get( 0 ).getLicenseComments().get() ); assertEquals( "SnippetName", snippets.get( 0 ).getName().get() ); assertEquals( "1231:3442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); assertEquals( "BSD-2-Clause", snippets.get( 0 ).getLicenseConcluded().toString() ); assertEquals( "BSD-2-Clause-FreeBSD", snippets.get( 0 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 0 ).getLicenseInfoFromFiles().size()] )[0].toString() ); - assertEquals( "44:55", TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); + assertEquals( "44:55", TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 0 ).getSnippetFromFile().getId() ); assertEquals( "Snippet Comment2", snippets.get( 1 ).getComment().get() ); @@ -790,11 +791,11 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet2 License Comment", snippets.get( 1 ).getLicenseComments().get() ); assertEquals( "SnippetName2", snippets.get( 1 ).getName().get() ); assertEquals( "31231:33442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); assertEquals( "MITNFA", snippets.get( 1 ).getLicenseConcluded().toString() ); assertEquals( "LicenseRef-testLicense", snippets.get( 1 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 1 ).getLicenseInfoFromFiles().size()] )[0].toString() ); assertEquals( "444:554", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 1 ).getSnippetFromFile().getId() ); //TODO Test dependencies } @@ -852,20 +853,18 @@ public void testExecuteUriNotUrl() throws Exception File artifactFile = getTestFile( "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.rdf.xml" ); assertTrue( artifactFile.exists() ); - ISerializableModelStore modelStore = new RdfStore(); - ModelCopyManager copyManager = new ModelCopyManager(); - SpdxDocument result; - String documentUri; - try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) - { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + try ( ISerializableModelStore modelStore = new RdfStore() ) { + SpdxDocument result; + try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) + { + result = (SpdxDocument)modelStore.deSerialize( is, false ); + } + List warnings = result.verify(); + assertEquals( 0, warnings.size() ); + // Test configuration parameters found in the test resources pom.xml file + // Document namespace + assertEquals( "spdx://sbom.foobar.dev/2.3/test-package-1.1.0", result.getDocumentUri() ); } - List warnings = result.verify(); - assertEquals( 0, warnings.size() ); - // Test configuration parameters found in the test resources pom.xml file - // Document namespace - assertEquals( "spdx://sbom.foobar.dev/2.3/test-package-1.1.0", result.getDocumentUri() ); } @Test @@ -888,11 +887,9 @@ public void testExecuteNoContributors() throws Exception ISerializableModelStore modelStore = new RdfStore(); ModelCopyManager copyManager = new ModelCopyManager(); SpdxDocument result; - String documentUri; try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + result = (SpdxDocument)modelStore.deSerialize( is, false ); } List warnings = result.verify(); assertEquals( 0, warnings.size() ); @@ -946,9 +943,9 @@ else if ( seeAlso.equals( "http://www.test.url/testLicense2-alt.html" ) ) assertEquals( "Document Comment", result.getComment().get() ); // documentAnnotations assertEquals( 2, result.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation1 = null; - org.spdx.library.model.Annotation annotation2 = null; - for ( org.spdx.library.model.Annotation annotation : result.getAnnotations() ) + org.spdx.library.model.v2.Annotation annotation1 = null; + org.spdx.library.model.v2.Annotation annotation2 = null; + for ( org.spdx.library.model.v2.Annotation annotation : result.getAnnotations() ) { if ( annotation.getComment().equals( "Annotation1" ) ) { @@ -994,16 +991,16 @@ else if ( creator.equals( "Person: Creator2" ) ) SpdxPackage pkg = (SpdxPackage) described; // packageAnnotations assertEquals( 1, pkg.getAnnotations().size() ); - org.spdx.library.model.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.Annotation [pkg.getAnnotations().size()] )[0]; + org.spdx.library.model.v2.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.v2.Annotation [pkg.getAnnotations().size()] )[0]; assertEquals( "PackageAnnotation", annotation.getComment() ); assertEquals( "2015-01-29T18:30:22Z", annotation.getAnnotationDate() ); assertEquals( "Person:Test Package Person", annotation.getAnnotator() ); assertEquals( AnnotationType.REVIEW, annotation.getAnnotationType() ); //licenseDeclared - AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseById( "BSD-2-Clause" ); + AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-2-Clause" ); assertEquals( licenseDeclared, pkg.getLicenseDeclared() ); //licenseConcluded - AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseById( "BSD-3-Clause" ); + AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseByIdCompatV2( "BSD-3-Clause" ); assertEquals( licenseConcluded, pkg.getLicenseConcluded() ); //licenseComments assertEquals( "License comments", pkg.getLicenseComments().get() ); @@ -1081,7 +1078,8 @@ else if ( externalRefs[0].getReferenceCategory().equals( } assertEquals( 0, filePaths.size() ); List snippets = new ArrayList<>(); - SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxSnippet.class ).forEach( (snippet) -> { + SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsCompatV2.CLASS_SPDX_SNIPPET, + null, result.getIdPrefix() ).forEach( (snippet) -> { snippets.add( (SpdxSnippet)snippet ); }); assertEquals( 2, snippets.size() ); @@ -1091,10 +1089,10 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet License Comment", snippets.get( 0 ).getLicenseComments().get() ); assertEquals( "SnippetName", snippets.get( 0 ).getName().get() ); assertEquals( "1231:3442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getByteRange() ) ); assertEquals( "BSD-2-Clause", snippets.get( 0 ).getLicenseConcluded().toString() ); assertEquals( "BSD-2-Clause-FreeBSD", snippets.get( 0 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 0 ).getLicenseInfoFromFiles().size()] )[0].toString() ); - assertEquals( "44:55", TestSpdxFileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); + assertEquals( "44:55", TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 0 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 0 ).getSnippetFromFile().getId() ); assertEquals( "Snippet Comment2", snippets.get( 1 ).getComment().get() ); @@ -1102,11 +1100,11 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( "Snippet2 License Comment", snippets.get( 1 ).getLicenseComments().get() ); assertEquals( "SnippetName2", snippets.get( 1 ).getName().get() ); assertEquals( "31231:33442", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getByteRange() ) ); assertEquals( "MITNFA", snippets.get( 1 ).getLicenseConcluded().toString() ); assertEquals( "LicenseRef-testLicense", snippets.get( 1 ).getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[snippets.get( 1 ).getLicenseInfoFromFiles().size()] )[0].toString() ); assertEquals( "444:554", - TestSpdxFileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); + TestSpdxV2FileCollector.startEndPointerToString( snippets.get( 1 ).getLineRange().get() ) ); assertEquals( fileWithSnippet, snippets.get( 1 ).getSnippetFromFile().getId() ); //TODO Test dependencies } @@ -1130,11 +1128,9 @@ public void testExecuteUseGeneratePurls() throws Exception ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); ModelCopyManager copyManager = new ModelCopyManager(); SpdxDocument result; - String documentUri; try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - documentUri = modelStore.deSerialize( is, false ); - result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + result = (SpdxDocument)modelStore.deSerialize( is, false ); } List warnings = result.verify(); assertEquals( 0, warnings.size() ); @@ -1143,8 +1139,9 @@ public void testExecuteUseGeneratePurls() throws Exception assertEquals( "http://spdx.org/documents/spdx%20toolsv2.0%20rc1", result.getDocumentUri() ); // purls List packages = new ArrayList<>(); - SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxPackage.class ).forEach( (pkg) -> { - packages.add( (SpdxPackage)pkg ); + SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsCompatV2.CLASS_SPDX_PACKAGE, + null, result.getIdPrefix() ).forEach( (pkg) -> { + packages.add( (SpdxPackage)pkg ); }); for ( SpdxPackage pkg : packages ) { Collection externalRefs = pkg.getExternalRefs(); diff --git a/src/test/java/org/spdx/maven/TestWithSessionSpdxMojo.java b/src/test/java/org/spdx/maven/TestWithSessionSpdxV2Mojo.java similarity index 87% rename from src/test/java/org/spdx/maven/TestWithSessionSpdxMojo.java rename to src/test/java/org/spdx/maven/TestWithSessionSpdxV2Mojo.java index 0ee240b..23d3d65 100644 --- a/src/test/java/org/spdx/maven/TestWithSessionSpdxMojo.java +++ b/src/test/java/org/spdx/maven/TestWithSessionSpdxV2Mojo.java @@ -28,24 +28,42 @@ import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; import org.spdx.jacksonstore.MultiFormatStore; import org.spdx.jacksonstore.MultiFormatStore.Format; -import org.spdx.library.InvalidSPDXAnalysisException; import org.spdx.library.ModelCopyManager; -import org.spdx.library.model.Relationship; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxModelFactory; -import org.spdx.library.model.SpdxPackage; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.Relationship; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxPackage; import org.spdx.spdxRdfStore.RdfStore; import org.spdx.storage.ISerializableModelStore; import org.spdx.storage.simple.InMemSpdxStore; -public class TestWithSessionSpdxMojo extends AbstractMojoTestCase +public class TestWithSessionSpdxV2Mojo extends AbstractMojoTestCase { private static final String UNIT_TEST_RESOURCE_DIR = "target/test-classes/unit/spdx-maven-plugin-test"; + + @Before + protected void setUp() throws Exception + { + super.setUp(); + SpdxModelFactory.init(); + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); + } + + @After + protected void tearDown() throws Exception + { + super.tearDown(); + } @Test public void testDependencies() throws Exception @@ -55,7 +73,7 @@ public void testDependencies() throws Exception Set packages = new HashSet<>(); Set relationships = new HashSet<>(); - SpdxModelFactory.getElements( result.getModelStore(), result.getDocumentUri(), result.getCopyManager(), SpdxPackage.class ) + SpdxModelFactory.getSpdxObjects( result.getModelStore(), result.getCopyManager(), SpdxConstantsCompatV2.CLASS_SPDX_PACKAGE, null, result.getIdPrefix() ) .forEach( ( element ) -> { SpdxPackage pkg = (SpdxPackage) element; try @@ -91,11 +109,9 @@ private SpdxDocument runMojoWithPom( File pom ) throws Exception assertTrue( artifactFile.exists() ); String outputFormat = (String) getVariableValueFromObject( mojo, "outputFormat" ); ISerializableModelStore modelStore = buildModelStore( outputFormat ); - ModelCopyManager copyManager = new ModelCopyManager(); try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) { - String documentUri = modelStore.deSerialize( is, false ); - return new SpdxDocument( modelStore, documentUri, copyManager, false ); + return (SpdxDocument)modelStore.deSerialize( is, false ); } } diff --git a/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java b/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java index c1f069b..29a3814 100644 --- a/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java +++ b/src/test/java/org/spdx/maven/utils/TestMavenToSpdxLicenseMapper.java @@ -13,12 +13,13 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; import org.spdx.library.ModelCopyManager; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.SpdxNoAssertionLicense; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v3_0_1.core.Element; import org.spdx.storage.simple.InMemSpdxStore; public class TestMavenToSpdxLicenseMapper @@ -31,6 +32,7 @@ public class TestMavenToSpdxLicenseMapper private static final String MIT_SPDX_ID = "MIT"; SpdxDocument spdxDoc = null; + Element spdxV3Doc = null; Log log = null; @@ -40,6 +42,7 @@ public class TestMavenToSpdxLicenseMapper @BeforeClass public static void setUpBeforeClass() throws Exception { + SpdxModelFactory.init(); } /** @@ -56,7 +59,10 @@ public static void tearDownAfterClass() throws Exception @Before public void setUp() throws Exception { + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); spdxDoc = new SpdxDocument( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL, new ModelCopyManager(), true ); + spdxV3Doc = new org.spdx.library.model.v3_0_1.software.SpdxPackage( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL + "/v3doc", + new ModelCopyManager(), true, TEST_SPDX_DOCUMENT_URL + "/"); } /** @@ -83,41 +89,75 @@ public void testGetMap() throws LicenseMapperException } @Test - public void testMavenLicenseListToSpdxLicenseNone() throws LicenseMapperException, InvalidSPDXAnalysisException + public void testMavenLicenseListToSpdxLicenseNoneV2() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( + org.spdx.library.model.v2.license.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList.subList( 0, 0 ), spdxDoc ); - assertEquals( new SpdxNoAssertionLicense(), result ); + assertEquals( new org.spdx.library.model.v2.license.SpdxNoAssertionLicense(), result ); + } + + @Test + public void testMavenLicenseListToSpdxLicenseNoneV3() throws LicenseMapperException, InvalidSPDXAnalysisException + { + List licenseList = new ArrayList<>(); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( + licenseList.subList( 0, 0 ), spdxV3Doc ); + assertEquals( new org.spdx.library.model.v3_0_1.expandedlicensing.NoAssertionLicense(), result ); } @Test - public void testMavenLicenseListToSpdxLicenseUnknown() throws LicenseMapperException, InvalidSPDXAnalysisException + public void testMavenLicenseListToSpdxLicenseUnknownV2() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); License license = new License(); license.setUrl( "http://not.a.known.url" ); licenseList.add( license ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( + org.spdx.library.model.v2.license.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); - assertEquals( new SpdxNoAssertionLicense(), result ); + assertEquals( new org.spdx.library.model.v2.license.SpdxNoAssertionLicense(), result ); + } + + @Test + public void testMavenLicenseListToSpdxLicenseUnknownV3() throws LicenseMapperException, InvalidSPDXAnalysisException + { + List licenseList = new ArrayList<>(); + License license = new License(); + license.setUrl( "http://not.a.known.url" ); + licenseList.add( license ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( + licenseList, spdxV3Doc ); + assertEquals( new org.spdx.library.model.v3_0_1.expandedlicensing.NoAssertionLicense(), result ); } @Test - public void testMavenLicenseListToSpdxLicenseSingle() throws LicenseMapperException, InvalidSPDXAnalysisException + public void testMavenLicenseListToSpdxLicenseSingleV2() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); License license = new License(); license.setUrl( APACHE2_URL ); licenseList.add( license ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( + org.spdx.library.model.v2.license.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); - AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); + org.spdx.library.model.v2.license.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( APACHE_SPDX_ID ); + assertEquals( expected, result ); + } + + @Test + public void testMavenLicenseListToSpdxLicenseSingleV3() throws LicenseMapperException, InvalidSPDXAnalysisException + { + List licenseList = new ArrayList<>(); + License license = new License(); + license.setUrl( APACHE2_URL ); + licenseList.add( license ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( + licenseList, spdxV3Doc ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); assertEquals( expected, result ); } @Test - public void testMavenLicenseListToSpdxLicenseConjunctive() throws LicenseMapperException, InvalidSPDXAnalysisException + public void testMavenLicenseListToSpdxLicenseConjunctiveV2() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); License license = new License(); @@ -126,14 +166,30 @@ public void testMavenLicenseListToSpdxLicenseConjunctive() throws LicenseMapperE License licenseM = new License(); licenseM.setUrl( MIT_URL ); licenseList.add( licenseM ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( + org.spdx.library.model.v2.license.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); - AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID + " AND " + MIT_SPDX_ID ); + org.spdx.library.model.v2.license.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( APACHE_SPDX_ID + " AND " + MIT_SPDX_ID ); + assertEquals( expected, result ); + } + + @Test + public void testMavenLicenseListToSpdxLicenseConjunctiveV3() throws LicenseMapperException, InvalidSPDXAnalysisException + { + List licenseList = new ArrayList<>(); + License license = new License(); + license.setUrl( APACHE2_URL ); + licenseList.add( license ); + License licenseM = new License(); + licenseM.setUrl( MIT_URL ); + licenseList.add( licenseM ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( + licenseList, spdxV3Doc ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID + " AND " + MIT_SPDX_ID ); assertEquals( expected, result ); } @Test - public void testMavenLicenseListToSpdxLicenseConunctiveUnknown() throws LicenseMapperException, InvalidSPDXAnalysisException + public void testMavenLicenseListToSpdxLicenseConunctiveUnknownV2() throws LicenseMapperException, InvalidSPDXAnalysisException { List licenseList = new ArrayList<>(); License license = new License(); @@ -142,9 +198,25 @@ public void testMavenLicenseListToSpdxLicenseConunctiveUnknown() throws LicenseM License licenseM = new License(); licenseM.setUrl( "http://unknown.url" ); licenseList.add( licenseM ); - AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( + org.spdx.library.model.v2.license.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV2License( licenseList, spdxDoc ); - AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); + org.spdx.library.model.v2.license.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( APACHE_SPDX_ID ); + assertEquals( expected, result ); + } + + @Test + public void testMavenLicenseListToSpdxLicenseConunctiveUnknownV3() throws LicenseMapperException, InvalidSPDXAnalysisException + { + List licenseList = new ArrayList<>(); + License license = new License(); + license.setUrl( APACHE2_URL ); + licenseList.add( license ); + License licenseM = new License(); + licenseM.setUrl( "http://unknown.url" ); + licenseList.add( licenseM ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo result = MavenToSpdxLicenseMapper.getInstance().mavenLicenseListToSpdxV3License( + licenseList, spdxV3Doc ); + org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo expected = LicenseInfoFactory.parseSPDXLicenseString( APACHE_SPDX_ID ); assertEquals( expected, result ); } } diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxSourceFileParser.java b/src/test/java/org/spdx/maven/utils/TestSpdxSourceFileParser.java index 0947596..5e25e48 100644 --- a/src/test/java/org/spdx/maven/utils/TestSpdxSourceFileParser.java +++ b/src/test/java/org/spdx/maven/utils/TestSpdxSourceFileParser.java @@ -8,12 +8,19 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.spdx.library.InvalidSPDXAnalysisException; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.ConjunctiveLicenseSet; -import org.spdx.library.model.license.DisjunctiveLicenseSet; -import org.spdx.library.model.license.ExtractedLicenseInfo; -import org.spdx.library.model.license.SpdxListedLicense; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.DefaultStoreNotInitialized; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.license.InvalidLicenseStringException; +import org.spdx.library.model.v3_0_1.expandedlicensing.ConjunctiveLicenseSet; +import org.spdx.library.model.v3_0_1.expandedlicensing.CustomLicense; +import org.spdx.library.model.v3_0_1.expandedlicensing.DisjunctiveLicenseSet; +import org.spdx.library.model.v3_0_1.expandedlicensing.ListedLicense; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.storage.simple.InMemSpdxStore; public class TestSpdxSourceFileParser { @@ -29,12 +36,13 @@ public class TestSpdxSourceFileParser private static final String MULTIPLE_SIMPLE_IDS = "Now is the time\n" + "SPDX-License-Identifier:" + APACHE_LICENSE_ID + "\nFor all good men" + " SPDX-License-Identifier: " + MIT_LICENSE_ID + "\nto come to the aid of their country."; private static final String MULTIPLE_COMPLEX_IDS = COMPLEX + "\nNow is the time\n" + "SPDX-License-Identifier:" + APACHE_LICENSE_ID + "\nFor all good men" + "\n SPDX-License-Identifier: " + MIT_LICENSE_ID + "\nto come to the aid of their country.\n" + COMPLEX_MULTI + "\n" + CONJUNCTIVE + "\n\n\nSPDX-License-Identifier:" + LICENSE_REF_ID; private static final String MISSMATCHED_PARENS = " SPDX-License-Identifier: (((" + MIT_LICENSE_ID + " OR \n" + APACHE_LICENSE_ID + ") OR \n" + APACHE_LICENSE_ID + ")"; - private static final String INVALID_EXPRESSION = " SPDX-License-Identifier: " + APACHE_LICENSE_ID + " NOTVALID " + MIT_LICENSE_ID + " AND " + LICENSE_REF_ID; private static final String TEST_CLASS_FILE_NAME = "target/test-classes/unit/ClassWithManySpdxIDs.java"; @Before public void setUp() throws Exception { + SpdxModelFactory.init(); + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); } @After @@ -56,57 +64,62 @@ private String getBaseDir() public void testParseFileForSpdxLicenses() throws SpdxSourceParserException, InvalidSPDXAnalysisException { File javaFile = new File( getBaseDir(), TEST_CLASS_FILE_NAME ); - List result = SpdxSourceFileParser.parseFileForSpdxLicenses( javaFile ); + List result = SpdxSourceFileParser.parseFileForSpdxLicenses( javaFile ); assertEquals( 3, result.size() ); - assertEquals( APACHE_LICENSE_ID, ( (SpdxListedLicense) result.get( 0 ) ).getLicenseId() ); - assertEquals( MIT_LICENSE_ID, ( (SpdxListedLicense) result.get( 1 ) ).getLicenseId() ); - assertTrue( result.get( 2 ) instanceof DisjunctiveLicenseSet ); - assertEquals( 2, ( (DisjunctiveLicenseSet) result.get( 2 ) ).getMembers().size() ); + assertEquals( APACHE_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 0 ) ) ).toString() ); + assertEquals( MIT_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 1 ) ) ).toString() ); + assertTrue( parseLic( result.get( 2 ) ) instanceof DisjunctiveLicenseSet ); + assertEquals( 2, ( (DisjunctiveLicenseSet) parseLic( result.get( 2 ) ) ).getMembers().size() ); + } + + private AnyLicenseInfo parseLic( String expression ) throws InvalidLicenseStringException, DefaultStoreNotInitialized + { + return LicenseInfoFactory.parseSPDXLicenseString( expression ); } @Test public void testParseTextForSpdxLicenses() throws SpdxSourceParserException, InvalidSPDXAnalysisException { // Empty String - List result = SpdxSourceFileParser.parseTextForSpdxLicenses( EMPTY ); + List result = SpdxSourceFileParser.parseTextForSpdxLicenses( EMPTY ); assertEquals( 0, result.size() ); // Simple single license ID result = SpdxSourceFileParser.parseTextForSpdxLicenses( SIMPLE ); assertEquals( 1, result.size() ); - assertEquals( APACHE_LICENSE_ID, ( (SpdxListedLicense) result.get( 0 ) ).getLicenseId() ); + assertEquals( APACHE_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 0 ) ) ).toString() ); // LicenseRef conjunctive result = SpdxSourceFileParser.parseTextForSpdxLicenses( CONJUNCTIVE ); assertEquals( 1, result.size() ); - assertTrue( result.get( 0 ) instanceof ConjunctiveLicenseSet ); - assertEquals( 3, ( (ConjunctiveLicenseSet) result.get( 0 ) ).getMembers().size() ); + assertTrue( parseLic( result.get( 0 ) ) instanceof ConjunctiveLicenseSet ); + assertEquals( 3, ( (ConjunctiveLicenseSet) parseLic( result.get( 0 ) ) ).getMembers().size() ); // Single Line complex result = SpdxSourceFileParser.parseTextForSpdxLicenses( COMPLEX ); assertEquals( 1, result.size() ); - assertTrue( result.get( 0 ) instanceof DisjunctiveLicenseSet ); - assertEquals( 2, ( (DisjunctiveLicenseSet) result.get( 0 ) ).getMembers().size() ); + assertTrue( parseLic( result.get( 0 ) ) instanceof DisjunctiveLicenseSet ); + assertEquals( 2, ( (DisjunctiveLicenseSet) parseLic( result.get( 0 ) ) ).getMembers().size() ); // Multi Line complex result = SpdxSourceFileParser.parseTextForSpdxLicenses( COMPLEX_MULTI ); assertEquals( 1, result.size() ); - assertTrue( result.get( 0 ) instanceof DisjunctiveLicenseSet ); - assertEquals( 2, ( (DisjunctiveLicenseSet) result.get( 0 ) ).getMembers().size() ); + assertTrue( parseLic( result.get( 0 ) ) instanceof DisjunctiveLicenseSet ); + assertEquals( 2, ( (DisjunctiveLicenseSet) parseLic( result.get( 0 ) ) ).getMembers().size() ); // Multiple SPDX ID's simple result = SpdxSourceFileParser.parseTextForSpdxLicenses( MULTIPLE_SIMPLE_IDS ); assertEquals( 2, result.size() ); - assertEquals( APACHE_LICENSE_ID, ( (SpdxListedLicense) result.get( 0 ) ).getLicenseId() ); - assertEquals( MIT_LICENSE_ID, ( (SpdxListedLicense) result.get( 1 ) ).getLicenseId() ); + assertEquals( APACHE_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 0 ) ) ).toString() ); + assertEquals( MIT_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 1 ) ) ).toString() ); // Multiple SPDX ID's complex result = SpdxSourceFileParser.parseTextForSpdxLicenses( MULTIPLE_COMPLEX_IDS ); assertEquals( 6, result.size() ); - assertTrue( result.get( 0 ) instanceof DisjunctiveLicenseSet ); - assertEquals( 2, ( (DisjunctiveLicenseSet) result.get( 0 ) ).getMembers().size() ); - assertEquals( APACHE_LICENSE_ID, ( (SpdxListedLicense) result.get( 1 ) ).getLicenseId() ); - assertEquals( MIT_LICENSE_ID, ( (SpdxListedLicense) result.get( 2 ) ).getLicenseId() ); - assertTrue( result.get( 3 ) instanceof DisjunctiveLicenseSet ); - assertEquals( 2, ( (DisjunctiveLicenseSet) result.get( 3 ) ).getMembers().size() ); - assertTrue( result.get( 4 ) instanceof ConjunctiveLicenseSet ); - assertEquals( 3, ( (ConjunctiveLicenseSet) result.get( 4 ) ).getMembers().size() ); - assertTrue( result.get( 5 ) instanceof ExtractedLicenseInfo ); - assertEquals( LICENSE_REF_ID, ( (ExtractedLicenseInfo) result.get( 5 ) ).getLicenseId() ); + assertTrue( parseLic( result.get( 0 ) ) instanceof DisjunctiveLicenseSet ); + assertEquals( 2, ( (DisjunctiveLicenseSet) parseLic( result.get( 0 ) ) ).getMembers().size() ); + assertEquals( APACHE_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 1 ) ) ).toString() ); + assertEquals( MIT_LICENSE_ID, ( (ListedLicense) parseLic( result.get( 2 ) ) ).toString() ); + assertTrue( parseLic( result.get( 3 ) ) instanceof DisjunctiveLicenseSet ); + assertEquals( 2, ( (DisjunctiveLicenseSet) parseLic( result.get( 3 ) ) ).getMembers().size() ); + assertTrue( parseLic( result.get( 4 ) ) instanceof ConjunctiveLicenseSet ); + assertEquals( 3, ( (ConjunctiveLicenseSet) parseLic( result.get( 4 ) ) ).getMembers().size() ); + assertTrue( parseLic( result.get( 5 ) ) instanceof CustomLicense ); + assertEquals( LICENSE_REF_ID, ( (CustomLicense) parseLic( result.get( 5 ) ) ).toString() ); // Miss matched parens (should error) try { @@ -117,16 +130,6 @@ public void testParseTextForSpdxLicenses() throws SpdxSourceParserException, Inv { //IGNORE - this is success } - // Invalid expression (should error) - try - { - result = SpdxSourceFileParser.parseTextForSpdxLicenses( INVALID_EXPRESSION ); - fail( "Invalid expression did not fail like it should" ); - } - catch ( SpdxSourceParserException ex ) - { - //IGNORE - this is success - } } } diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxFileCollector.java b/src/test/java/org/spdx/maven/utils/TestSpdxV2FileCollector.java similarity index 85% rename from src/test/java/org/spdx/maven/utils/TestSpdxFileCollector.java rename to src/test/java/org/spdx/maven/utils/TestSpdxV2FileCollector.java index 992a13d..fc276fe 100644 --- a/src/test/java/org/spdx/maven/utils/TestSpdxFileCollector.java +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV2FileCollector.java @@ -24,37 +24,39 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; - -import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; import org.spdx.library.ModelCopyManager; -import org.spdx.library.SpdxConstants; -import org.spdx.library.model.Checksum; -import org.spdx.library.model.Relationship; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.SpdxFile; -import org.spdx.library.model.SpdxPackage; -import org.spdx.library.model.SpdxPackageVerificationCode; -import org.spdx.library.model.SpdxSnippet; -import org.spdx.library.model.enumerations.ChecksumAlgorithm; -import org.spdx.library.model.enumerations.FileType; -import org.spdx.library.model.enumerations.RelationshipType; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.pointer.ByteOffsetPointer; -import org.spdx.library.model.pointer.LineCharPointer; -import org.spdx.library.model.pointer.SinglePointer; -import org.spdx.library.model.pointer.StartEndPointer; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.Relationship; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.SpdxFile; +import org.spdx.library.model.v2.SpdxPackage; +import org.spdx.library.model.v2.SpdxPackageVerificationCode; +import org.spdx.library.model.v2.SpdxSnippet; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v2.enumerations.FileType; +import org.spdx.library.model.v2.enumerations.RelationshipType; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.pointer.ByteOffsetPointer; +import org.spdx.library.model.v2.pointer.LineCharPointer; +import org.spdx.library.model.v2.pointer.SinglePointer; +import org.spdx.library.model.v2.pointer.StartEndPointer; +import org.spdx.maven.Checksum; import org.spdx.maven.SnippetInfo; import org.spdx.storage.simple.InMemSpdxStore; -public class TestSpdxFileCollector +public class TestSpdxV2FileCollector { @BeforeClass public static void setUpBeforeClass() throws Exception { + SpdxModelFactory.init(); } @AfterClass @@ -85,10 +87,10 @@ public static void tearDownAfterClass() throws Exception private static final String DEFAULT_SNIPPET_LICENSE_COMMENT = "Snippet License Comment"; private static final String DEFAULT_SNIPPET_COPYRIGHT = "Snippet Copyright"; - private static final Set sha1Algorithm = new HashSet<>(); + private static final Set sha1Algorithm = new HashSet<>(); static { - sha1Algorithm.add( ChecksumAlgorithm.SHA1 ); + sha1Algorithm.add( ChecksumAlgorithm.SHA1.toString() ); } private SpdxDefaultFileInformation defaultFileInformation; @@ -102,17 +104,18 @@ public static void tearDownAfterClass() throws Exception @Before public void setUp() throws Exception { + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); spdxDoc = new SpdxDocument( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL, new ModelCopyManager(), true ); this.defaultFileInformation = new SpdxDefaultFileInformation(); this.defaultFileInformation.setComment( DEFAULT_COMMENT ); - AnyLicenseInfo concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( DEFAULT_CONCLUDED_LICENSE, - spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); - this.defaultFileInformation.setConcludedLicense( concludedLicense ); + AnyLicenseInfo concludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( DEFAULT_CONCLUDED_LICENSE, + spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); + this.defaultFileInformation.setConcludedLicense( DEFAULT_CONCLUDED_LICENSE ); this.defaultFileInformation.setContributors( DEFAULT_CONTRIBUTORS ); this.defaultFileInformation.setCopyright( DEFAULT_COPYRIGHT ); - AnyLicenseInfo declaredLicense = LicenseInfoFactory.parseSPDXLicenseString( DEFAULT_DECLARED_LICENSE, + AnyLicenseInfo declaredLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( DEFAULT_DECLARED_LICENSE, spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() ); - this.defaultFileInformation.setDeclaredLicense( declaredLicense ); + this.defaultFileInformation.setDeclaredLicense( DEFAULT_DECLARED_LICENSE ); this.defaultFileInformation.setLicenseComment( DEFAULT_LICENSE_COMMENT ); this.defaultFileInformation.setNotice( DEFAULT_NOTICE ); SnippetInfo si = new SnippetInfo(); @@ -128,7 +131,7 @@ public void setUp() throws Exception snippets.add( si ); this.defaultFileInformation.setSnippets( snippets ); - this.directory = Files.createTempDirectory( "spdxfilecollector" ).toFile(); + this.directory = Files.createTempDirectory( "SpdxV2FileCollector" ).toFile(); int numFiles = FILE_NAMES.length; for ( String[] subdirFile : SUBDIR_FILES ) { @@ -173,7 +176,7 @@ public void setUp() throws Exception dirFileSet.setDirectory( directory.getPath() ); dirFileSet.setOutputDirectory( this.directory.getName() ); this.fileSets = Arrays.asList( dirFileSet ); - this.spdxPackage = spdxDoc.createPackage( SpdxConstants.SPDX_ELEMENT_REF_PRENUM+"test", + this.spdxPackage = spdxDoc.createPackage( SpdxConstantsCompatV2.SPDX_ELEMENT_REF_PRENUM+"test", "TestPackage", concludedLicense, "Package copyright", @@ -232,9 +235,9 @@ else if ( child.isDirectory() ) } @Test - public void testSpdxFileCollector() throws InvalidSPDXAnalysisException + public void testSpdxV2FileCollector() throws InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); Collection files = collector.getFiles(); assertEquals( 0, files.size() ); } @@ -242,7 +245,7 @@ public void testSpdxFileCollector() throws InvalidSPDXAnalysisException @Test public void testCollectFilesInDirectory() throws InvalidSPDXAnalysisException, SpdxCollectionException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); assertEquals( 0, SpdxFiles.length ); @@ -268,7 +271,7 @@ public void testCollectFileInDirectoryPattern() throws SpdxCollectionException, skipBin.setDirectory( this.fileSets.get(0).getDirectory() ); skipBin.addExclude( "**/*.bin" ); skipBin.setOutputDirectory( this.fileSets.get(0).getOutputDirectory() ); - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); assertEquals( 0, SpdxFiles.length ); @@ -291,7 +294,7 @@ public void testCollectFileInDirectoryPattern() throws SpdxCollectionException, @Test public void testGetExtension() throws InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); File noExtension = new File( "noextension" ); String result = collector.getExtension( noExtension ); assertTrue( result.isEmpty() ); @@ -310,14 +313,14 @@ public void testGetExtension() throws InvalidSPDXAnalysisException @Test public void testExtensionToFileType() throws InvalidSPDXAnalysisException { - assertEquals( FileType.VIDEO, SpdxFileCollector.extensionToFileType( "SWF" )); - assertEquals( FileType.OTHER, SpdxFileCollector.extensionToFileType( "somerandom" )); + assertEquals( FileType.VIDEO, SpdxV2FileCollector.extensionToFileType( "SWF" )); + assertEquals( FileType.OTHER, SpdxV2FileCollector.extensionToFileType( "somerandom" )); } @Test public void testGetFiles() throws SpdxCollectionException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); assertEquals( 0, SpdxFiles.length ); @@ -335,8 +338,8 @@ public void testGetFiles() throws SpdxCollectionException, InvalidSPDXAnalysisEx assertEquals( DEFAULT_COPYRIGHT, SpdxFiles[i].getCopyrightText() ); if ( SpdxFileNames[i].endsWith( FILE_NAME_WITH_ID ) ) { - assertEquals(LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS_DECLARED_LICENSE ), SpdxFiles[i].getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[SpdxFiles[i].getLicenseInfoFromFiles().size()] )[0] ); - assertEquals( LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS__CONCLUDED_LICENSE ), SpdxFiles[i].getLicenseConcluded() ); + assertEquals(LicenseInfoFactory.parseSPDXLicenseStringCompatV2( FILE_WITH_IDS_DECLARED_LICENSE ), SpdxFiles[i].getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[SpdxFiles[i].getLicenseInfoFromFiles().size()] )[0] ); + assertEquals( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( FILE_WITH_IDS__CONCLUDED_LICENSE ), SpdxFiles[i].getLicenseConcluded() ); } else { @@ -351,7 +354,7 @@ public void testGetFiles() throws SpdxCollectionException, InvalidSPDXAnalysisEx @Test public void testGetSnippets() throws SpdxCollectionException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); List snippets = collector.getSnippets(); assertEquals( 0, snippets.size() ); @@ -398,20 +401,20 @@ else if ( pointer instanceof LineCharPointer ) @Test public void testCollectFilesWithPattern() throws SpdxCollectionException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); assertEquals( 0, SpdxFiles.length ); HashMap fileSpecificInfo = new HashMap<>(); SpdxDefaultFileInformation file2Info = new SpdxDefaultFileInformation(); String file2Comment = "File 2 comment"; file2Info.setComment( file2Comment ); - AnyLicenseInfo file2License = defaultFileInformation.getDeclaredLicense(); + String file2License = defaultFileInformation.getDeclaredLicense(); file2Info.setConcludedLicense( file2License ); String[] file2Contributors = new String[] {"Person: File 2 contributor"}; file2Info.setContributors( file2Contributors ); String file2Copyright = "File 2 copyright"; file2Info.setCopyright( file2Copyright ); - AnyLicenseInfo file2DeclaredLicense = defaultFileInformation.getConcludedLicense(); + String file2DeclaredLicense = defaultFileInformation.getConcludedLicense(); file2Info.setDeclaredLicense( file2DeclaredLicense ); String file2LicenseComment = "File 2 license comment"; file2Info.setLicenseComment( file2LicenseComment ); @@ -424,13 +427,13 @@ public void testCollectFilesWithPattern() throws SpdxCollectionException, Invali SpdxDefaultFileInformation file3Info = new SpdxDefaultFileInformation(); String file3Comment = "File 3 comment"; file3Info.setComment( file3Comment ); - AnyLicenseInfo file3License = defaultFileInformation.getDeclaredLicense(); + String file3License = defaultFileInformation.getDeclaredLicense(); file3Info.setConcludedLicense( file3License ); String[] file3Contributors = new String[] {"Person: File 3 contributor"}; file3Info.setContributors( file3Contributors ); String file3Copyright = "File 3 copyright"; file3Info.setCopyright( file3Copyright ); - AnyLicenseInfo file3DeclaredLicense = defaultFileInformation.getDeclaredLicense(); + String file3DeclaredLicense = defaultFileInformation.getDeclaredLicense(); file3Info.setDeclaredLicense( file3DeclaredLicense ); String file3LicenseComment = "File 3 license comment"; file3Info.setLicenseComment( file3LicenseComment ); @@ -451,14 +454,14 @@ public void testCollectFilesWithPattern() throws SpdxCollectionException, Invali assertEquals( SpdxFileNames[i], SpdxFiles[i].getName().get() ); if ( SpdxFiles[i].getName().get().equals( SpdxFileNames[1] ) ) { - assertEquals( file2Comment, SpdxFiles[1].getComment().get() ); - assertEquals( file2License.toString(), SpdxFiles[1].getLicenseConcluded().toString() ); - assertEquals( file2Contributors.length, SpdxFiles[1].getFileContributors().size() ); - assertArrayEquals( file2Contributors, TestUtils.toSortedArray( SpdxFiles[1].getFileContributors() ) ); - assertEquals( file2Copyright, SpdxFiles[1].getCopyrightText() ); - assertEquals( file2DeclaredLicense.toString(), SpdxFiles[1].getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[SpdxFiles[1].getLicenseInfoFromFiles().size()] )[0].toString() ); - assertEquals( file2LicenseComment, SpdxFiles[1].getLicenseComments().get() ); - assertEquals( file2Notice, SpdxFiles[1].getNoticeText().get() ); + assertEquals( file2Comment, SpdxFiles[i].getComment().get() ); + assertEquals( file2License.toString(), SpdxFiles[i].getLicenseConcluded().toString() ); + assertEquals( file2Contributors.length, SpdxFiles[i].getFileContributors().size() ); + assertArrayEquals( file2Contributors, TestUtils.toSortedArray( SpdxFiles[i].getFileContributors() ) ); + assertEquals( file2Copyright, SpdxFiles[i].getCopyrightText() ); + assertEquals( file2DeclaredLicense.toString(), SpdxFiles[i].getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[SpdxFiles[1].getLicenseInfoFromFiles().size()] )[0].toString() ); + assertEquals( file2LicenseComment, SpdxFiles[i].getLicenseComments().get() ); + assertEquals( file2Notice, SpdxFiles[i].getNoticeText().get() ); } else if ( SpdxFiles[i].getName().get().startsWith( subDirAPrefix ) ) { @@ -488,7 +491,7 @@ else if ( !SpdxFiles[i].getName().get().endsWith( FILE_NAME_WITH_ID ) ) @Test public void testGetLicenseInfoFromFiles() throws SpdxCollectionException, IOException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); AnyLicenseInfo[] result = collector.getLicenseInfoFromFiles().toArray( new AnyLicenseInfo[collector.getLicenseInfoFromFiles().size()] ); assertEquals( 0, result.length ); @@ -499,7 +502,7 @@ public void testGetLicenseInfoFromFiles() throws SpdxCollectionException, IOExce assertEquals( 2, result.length ); if ( DEFAULT_DECLARED_LICENSE.equals( result[0].toString() ) ) { - assertEquals( LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS_DECLARED_LICENSE ), result[1] ); + assertEquals( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( FILE_WITH_IDS_DECLARED_LICENSE ), result[1] ); } else { @@ -517,7 +520,7 @@ public void testGetLicenseInfoFromFiles() throws SpdxCollectionException, IOExce info2.setConcludedLicense( this.defaultFileInformation.getConcludedLicense() ); info2.setCopyright( this.defaultFileInformation.getCopyright() ); String newLicenseName = "LicenseRef-newLicense"; - AnyLicenseInfo newDeclaredLicense = LicenseInfoFactory.parseSPDXLicenseString( newLicenseName ); + String newDeclaredLicense = newLicenseName ; info2.setDeclaredLicense( newDeclaredLicense ); FileSet fileSet2 = new FileSet(); fileSet2.setDirectory( tempDir2.getPath() ); @@ -529,8 +532,8 @@ public void testGetLicenseInfoFromFiles() throws SpdxCollectionException, IOExce boolean foundDefault = false; boolean foundFileWithIds = false; boolean foundNewLicense = false; - AnyLicenseInfo defaultDecaredLicense = LicenseInfoFactory.parseSPDXLicenseString( DEFAULT_DECLARED_LICENSE ); - AnyLicenseInfo fileWithIdstDecaredLicense = LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS_DECLARED_LICENSE ); + AnyLicenseInfo defaultDecaredLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( DEFAULT_DECLARED_LICENSE ); + AnyLicenseInfo fileWithIdstDecaredLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( FILE_WITH_IDS_DECLARED_LICENSE ); for ( AnyLicenseInfo lic : result ) { if ( lic.equals( defaultDecaredLicense ) ) @@ -559,7 +562,7 @@ public void testGetLicenseInfoFromFiles() throws SpdxCollectionException, IOExce @Test public void testGetVerificationCode() throws SpdxCollectionException, NoSuchAlgorithmException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); assertEquals( 0, SpdxFiles.length ); @@ -577,7 +580,7 @@ public void testConvertChecksumToString() { byte[] cksumBytes = new byte[] {00, 01, 02, 03, 04, 05, 06, 07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1E}; String expected = "000102030405060708090a0b0c0d1e"; - String result = SpdxFileCollector.convertChecksumToString( cksumBytes ); + String result = SpdxV2FileCollector.convertChecksumToString( cksumBytes ); assertEquals( expected, result ); } @@ -586,7 +589,7 @@ public void testConvertFilePathToSpdxFileName() { String dosFilePath = "subdir\\subdir2\\file.c"; String dosSpdxFile = "./subdir/subdir2/file.c"; - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); String result = collector.convertFilePathToSpdxFileName( dosFilePath ); assertEquals( dosSpdxFile, result ); @@ -599,7 +602,7 @@ public void testConvertFilePathToSpdxFileName() @Test public void testIsSourceFile() { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); assertTrue( collector.isSourceFile( toFileTypeCollection( new FileType[] {FileType.SOURCE} ) ) ); assertTrue( collector.isSourceFile( toFileTypeCollection( new FileType[] {FileType.TEXT, FileType.SOURCE} ) ) ); assertFalse( collector.isSourceFile( toFileTypeCollection( new FileType[] {FileType.BINARY, FileType.IMAGE} ) ) ); @@ -621,20 +624,20 @@ private Collection toFileTypeCollection( FileType[] fileTypes ) @Test public void testGenerateChecksums() throws SpdxCollectionException, InvalidSPDXAnalysisException { - SpdxFileCollector collector = new SpdxFileCollector(); + SpdxV2FileCollector collector = new SpdxV2FileCollector(); collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); File spdxFile = new File( filePaths[0] ); - Set checksumAlgorithmSet = new HashSet<>(); - checksumAlgorithmSet.add(ChecksumAlgorithm.SHA1 ); - checksumAlgorithmSet.add( ChecksumAlgorithm.SHA256 ); + Set checksumAlgorithmSet = new HashSet<>(); + checksumAlgorithmSet.add(ChecksumAlgorithm.SHA1.toString() ); + checksumAlgorithmSet.add( ChecksumAlgorithm.SHA256.toString() ); Set expectedChecksums = new HashSet<>(); - expectedChecksums.add( spdxDoc.createChecksum( ChecksumAlgorithm.SHA1, "1834453c87b9188024c7b18d179eb64f95f29fcf" ) ); - expectedChecksums.add( spdxDoc.createChecksum( ChecksumAlgorithm.SHA256, "1c94046c63f61f5dbe5c15cc6c4e34510132ab262aa266735b344d836ef8cb3c") ); + expectedChecksums.add( new Checksum( ChecksumAlgorithm.SHA1.toString(), "1834453c87b9188024c7b18d179eb64f95f29fcf" ) ); + expectedChecksums.add( new Checksum( ChecksumAlgorithm.SHA256.toString(), "1c94046c63f61f5dbe5c15cc6c4e34510132ab262aa266735b344d836ef8cb3c") ); // Checksum does not override equals currently. Hence, need to compare manually - Set actualChecksums = SpdxFileCollector.generateChecksum( spdxFile, checksumAlgorithmSet, spdxDoc ); + Set actualChecksums = SpdxV2FileCollector.generateChecksum( spdxFile, checksumAlgorithmSet ); for ( Checksum expectedChecksum : expectedChecksums ) { boolean found = false; diff --git a/src/test/java/org/spdx/maven/utils/TestLicenseManager.java b/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java similarity index 94% rename from src/test/java/org/spdx/maven/utils/TestLicenseManager.java rename to src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java index 2e0af47..1d822cc 100644 --- a/src/test/java/org/spdx/maven/utils/TestLicenseManager.java +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java @@ -27,14 +27,16 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; import org.spdx.library.ModelCopyManager; -import org.spdx.library.model.SpdxDocument; -import org.spdx.library.model.license.AnyLicenseInfo; -import org.spdx.library.model.license.ConjunctiveLicenseSet; -import org.spdx.library.model.license.ExtractedLicenseInfo; -import org.spdx.library.model.license.LicenseInfoFactory; -import org.spdx.library.model.license.SpdxListedLicense; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.SpdxDocument; +import org.spdx.library.model.v2.license.AnyLicenseInfo; +import org.spdx.library.model.v2.license.ConjunctiveLicenseSet; +import org.spdx.library.model.v2.license.ExtractedLicenseInfo; +import org.spdx.library.model.v2.license.SpdxListedLicense; import org.spdx.maven.NonStandardLicense; import org.spdx.storage.simple.InMemSpdxStore; import org.apache.maven.model.License; @@ -44,7 +46,7 @@ * * @author Gary O'Neall */ -public class TestLicenseManager +public class TestSpdxV2LicenseManager { private static final String TEST_SPDX_DOCUMENT_URL = "http://www.spdx.org/documents/test"; static final String APACHE_CROSS_REF_URL2 = "http://www.apache.org/licenses/LICENSE-2.0"; @@ -63,6 +65,7 @@ public class TestLicenseManager @BeforeClass public static void setUpBeforeClass() throws Exception { + SpdxModelFactory.init(); } /** @@ -79,6 +82,7 @@ public static void tearDownAfterClass() throws Exception @Before public void setUp() throws Exception { + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); spdxDoc = new SpdxDocument( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL, new ModelCopyManager(), true ); } @@ -269,7 +273,7 @@ public void testSpdxLicenseToMavenLicense() throws LicenseManagerException, Lice { SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); // standard license - AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseString( APACHE_LICENSE_ID ); + AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( APACHE_LICENSE_ID ); License result = licenseManager.spdxLicenseToMavenLicense( licenseInfo ); assertEquals( result.getName(), ( (SpdxListedLicense) licenseInfo ).getName() ); String resultUrl = result.getUrl().replace( "https", "http" ); diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxV3FileCollector.java b/src/test/java/org/spdx/maven/utils/TestSpdxV3FileCollector.java new file mode 100644 index 0000000..9cd03c1 --- /dev/null +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV3FileCollector.java @@ -0,0 +1,665 @@ +package org.spdx.maven.utils; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.shared.model.fileset.FileSet; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v2.SpdxConstantsCompatV2; +import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; +import org.spdx.library.model.v3_0_1.core.DictionaryEntry; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.core.PositiveIntegerRange; +import org.spdx.library.model.v3_0_1.core.Relationship; +import org.spdx.library.model.v3_0_1.core.RelationshipType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.library.model.v3_0_1.software.Snippet; +import org.spdx.library.model.v3_0_1.software.SpdxFile; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.maven.Checksum; +import org.spdx.maven.SnippetInfo; +import org.spdx.storage.simple.InMemSpdxStore; + + +public class TestSpdxV3FileCollector +{ + + + @BeforeClass + public static void setUpBeforeClass() throws Exception + { + SpdxModelFactory.init(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception + { + } + private static final String TEST_SPDX_DOCUMENT_URL = "http://www.spdx.org/documents/test"; + static final String[] FILE_NAMES = new String[] {"file1.bin", "file2.c", "file3.php", "file4.zip"}; + static final String FILE_NAME_WITH_ID = "FileWithSpdxIds.java"; + static final String FILE_WITH_ID_CONTENT = "/**\n *SPDX-License-Identifier: MIT\n *\n *SPDX-License-Identifier: Apache-2.0\n**/"; + static final String FILE_WITH_IDS_DECLARED_LICENSE = "(MIT AND Apache-2.0)"; + static final String FILE_WITH_IDS__CONCLUDED_LICENSE = FILE_WITH_IDS_DECLARED_LICENSE; + static final String SNIPPET_NAMES = "Snippet Name"; + static final String[] SUB_DIRS = new String[] {"dirA", "folderB"}; + static final String[][] SUBDIR_FILES = new String[][] {new String[] {"subfile1.c", "subfile2.bin"}, new String[] {"sub2files.php"}}; + private static final String DEFAULT_COMMENT = "Default comment"; + private static final String DEFAULT_CONCLUDED_LICENSE = "Apache-2.0"; + private static final String[] DEFAULT_CONTRIBUTORS = new String[] {"Contrib1", "Contrib2"}; + private static final String DEFAULT_COPYRIGHT = "Default copyright"; + private static final String DEFAULT_DECLARED_LICENSE = "APSL-1.1"; + private static final String DEFAULT_LICENSE_COMMENT = "Default license comment"; + private static final String DEFAULT_NOTICE = "Default notice"; + private static final String DEFAULT_SNIPPET_BYTE_RANGE = "12:5234"; + private static final String DEFAULT_SNIPPET_LINE_RANGE = "88:99"; + private static final String DEFAULT_SNIPPET_COMMENT = "Snippet comment"; + private static final String DEFAULT_SNIPPET_CONCLUDED_LICENSE = "CC-BY-3.0"; + private static final String DEFAULT_SNIPPET_DECLARED_LICENSE = "LGPL-2.0"; + private static final String DEFAULT_SNIPPET_LICENSE_COMMENT = "Snippet License Comment"; + private static final String DEFAULT_SNIPPET_COPYRIGHT = "Snippet Copyright"; + + private static final Set sha1Algorithm = new HashSet<>(); + static + { + sha1Algorithm.add( ChecksumAlgorithm.SHA1.toString() ); + } + + private SpdxDefaultFileInformation defaultFileInformation; + private File directory; + private String[] filePaths; + private String[] SpdxFileNames; + private List fileSets; + private SpdxPackage spdxPackage; + private List customIdMap = new ArrayList<>(); + SpdxDocument spdxDoc = null; + Comparator elementComparer = new Comparator() { + + @Override + public int compare( Element o1, Element o2 ) + { + try + { + return o1.getName().orElse( "" ).compareTo(o2.getName().orElse( "" )); + } + catch ( InvalidSPDXAnalysisException e ) + { + fail( "Error getting element names" ); + return 0; + } + } + + }; + + @Before + public void setUp() throws Exception + { + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); + spdxDoc = new SpdxDocument( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL + "/Document", new ModelCopyManager(), true, TEST_SPDX_DOCUMENT_URL + "/" ); + this.defaultFileInformation = new SpdxDefaultFileInformation(); + this.defaultFileInformation.setComment( DEFAULT_COMMENT ); + AnyLicenseInfo concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( DEFAULT_CONCLUDED_LICENSE, spdxDoc.getModelStore(), + spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdMap ); + this.defaultFileInformation.setConcludedLicense( DEFAULT_CONCLUDED_LICENSE ); + this.defaultFileInformation.setContributors( DEFAULT_CONTRIBUTORS ); + this.defaultFileInformation.setCopyright( DEFAULT_COPYRIGHT ); + AnyLicenseInfo declaredLicense = LicenseInfoFactory.parseSPDXLicenseString( DEFAULT_DECLARED_LICENSE, + spdxDoc.getModelStore(), spdxDoc.getIdPrefix(), + spdxDoc.getCopyManager(), customIdMap ); + this.defaultFileInformation.setDeclaredLicense( DEFAULT_DECLARED_LICENSE ); + this.defaultFileInformation.setLicenseComment( DEFAULT_LICENSE_COMMENT ); + this.defaultFileInformation.setNotice( DEFAULT_NOTICE ); + SnippetInfo si = new SnippetInfo(); + si.setByteRange( DEFAULT_SNIPPET_BYTE_RANGE ); + si.setComment( DEFAULT_SNIPPET_COMMENT ); + si.setConcludedLicense( DEFAULT_SNIPPET_CONCLUDED_LICENSE ); + si.setLicenseInfoInSnippet( DEFAULT_SNIPPET_DECLARED_LICENSE ); + si.setLicenseComment( DEFAULT_SNIPPET_LICENSE_COMMENT ); + si.setCopyrightText( DEFAULT_SNIPPET_COPYRIGHT ); + si.setLineRange( DEFAULT_SNIPPET_LINE_RANGE ); + si.setName( SNIPPET_NAMES ); + ArrayList snippets = new ArrayList<>(); + snippets.add( si ); + this.defaultFileInformation.setSnippets( snippets ); + + this.directory = Files.createTempDirectory( "SpdxV3FileCollector" ).toFile(); + int numFiles = FILE_NAMES.length; + for ( String[] subdirFile : SUBDIR_FILES ) + { + numFiles = numFiles + subdirFile.length; + } + numFiles++; // for the SPDX file with license IDs + this.filePaths = new String[numFiles]; + this.SpdxFileNames = new String[numFiles]; + int fpi = 0; // file path index + for ( String fileName : FILE_NAMES ) + { + File newFile = new File( this.directory.getPath() + File.separator + fileName ); + newFile.createNewFile(); + createUniqueContent( newFile ); + this.filePaths[fpi] = newFile.getPath(); + this.SpdxFileNames[fpi++] = "./" + this.directory.getName() + "/" + fileName; + } + for ( int i = 0; i < SUB_DIRS.length; i++ ) + { + File newDir = new File( this.directory.getPath() + File.separator + SUB_DIRS[i] ); + newDir.mkdir(); + for ( int j = 0; j < SUBDIR_FILES[i].length; j++ ) + { + File newFile = new File( newDir.getPath() + File.separator + SUBDIR_FILES[i][j] ); + newFile.createNewFile(); + createUniqueContent( newFile ); + this.filePaths[fpi] = newFile.getPath(); + this.SpdxFileNames[fpi++] = "./" + this.directory.getName() + "/" + SUB_DIRS[i] + "/" + SUBDIR_FILES[i][j]; + } + } + File fileWithIds = new File( this.directory.getPath() + File.separator + FILE_NAME_WITH_ID ); + fileWithIds.createNewFile(); + try ( PrintWriter writer = new PrintWriter( fileWithIds ) ) + { + writer.print( FILE_WITH_ID_CONTENT ); + } + this.filePaths[fpi] = fileWithIds.getPath(); + this.SpdxFileNames[fpi++] = "./" + this.directory.getName() + "/" + FILE_NAME_WITH_ID; + Arrays.sort( this.filePaths ); + Arrays.sort( SpdxFileNames ); + FileSet dirFileSet = new FileSet(); + dirFileSet.setDirectory( directory.getPath() ); + dirFileSet.setOutputDirectory( this.directory.getName() ); + this.fileSets = Arrays.asList( dirFileSet ); + this.spdxPackage = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + SpdxConstantsCompatV2.SPDX_ELEMENT_REF_PRENUM+"test" ) + .setName( "TestPackage" ) + .setCopyrightText( "Package copyright" ) + .setDownloadLocation( "NOASSERTION" ) + .build(); + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + SpdxConstantsCompatV2.SPDX_ELEMENT_REF_PRENUM+"pkgdeclared" ) + .addTo( declaredLicense ) + .setFrom( spdxPackage ) + .setRelationshipType( RelationshipType.HAS_DECLARED_LICENSE ) + .build(); + spdxDoc.createRelationship( spdxDoc.getIdPrefix() + SpdxConstantsCompatV2.SPDX_ELEMENT_REF_PRENUM+"pkgconcluded" ) + .addTo( concludedLicense ) + .setFrom( spdxPackage ) + .setRelationshipType( RelationshipType.HAS_CONCLUDED_LICENSE ) + .build(); + } + + private void createUniqueContent( File file ) throws FileNotFoundException + { + try ( PrintWriter writer = new PrintWriter( file ) ) + { + writer.println( file.getPath() ); + writer.println( System.nanoTime() ); + } + } + + @After + public void tearDown() throws Exception + { + spdxDoc = null; + deleteDirectory( this.directory ); + } + + private void deleteDirectory( File dir ) + { + if ( dir.isFile() ) + { + if ( !dir.delete() ) + { + System.console().writer().println( "Unable to delete " + dir.getPath() ); + } + } + else if ( dir.isDirectory() ) + { + File[] children = dir.listFiles(); + if ( children != null ) + { + for ( File child : children ) + { + if ( child.isFile() ) + { + if ( !child.delete() ) + { + System.console().writer().println( "Unable to delete " + child.getPath() ); + } + } + else if ( child.isDirectory() ) + { + deleteDirectory( child ); + } + } + } + } + } + + @Test + public void testSpdxV3FileCollector() throws InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + Collection files = collector.getFiles(); + assertEquals( 0, files.size() ); + } + + @Test + public void testCollectFilesInDirectory() throws InvalidSPDXAnalysisException, SpdxCollectionException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + SpdxFile[] spdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( 0, spdxFiles.length ); + + collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, + new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + spdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( filePaths.length, spdxFiles.length ); + Arrays.sort( spdxFiles, elementComparer ); + @SuppressWarnings( "unchecked" ) + List allRelationships = (List)SpdxModelFactory + .getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.CORE_RELATIONSHIP, + null, spdxDoc.getIdPrefix() ).collect( Collectors.toList() ); + for ( int i = 0; i < spdxFiles.length; i++ ) + { + boolean foundGenerates = false; + for ( Relationship relationship : allRelationships ) + { + if ( relationship.getFrom().equals( spdxFiles[i] ) && + RelationshipType.GENERATES.equals( relationship.getRelationshipType() ) ) + { + Element[] tos = relationship.getTos().toArray( new Element[relationship.getTos().size()] ); + assertEquals( 1, tos.length ); + assertEquals( spdxPackage, tos[0] ); + foundGenerates = true; + break; + } + } + assertTrue( foundGenerates ); + } + } + + @Test + public void testCollectFileInDirectoryPattern() throws SpdxCollectionException, InvalidSPDXAnalysisException + { + FileSet skipBin = new FileSet(); + skipBin.setDirectory( this.fileSets.get(0).getDirectory() ); + skipBin.addExclude( "**/*.bin" ); + skipBin.setOutputDirectory( this.fileSets.get(0).getOutputDirectory() ); + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( 0, SpdxFiles.length ); + + collector.collectFiles( Arrays.asList( skipBin ), this.directory.getAbsolutePath(), this.defaultFileInformation, + new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( filePaths.length - 2, SpdxFiles.length ); + Arrays.sort( SpdxFiles, elementComparer ); + int SpdxFilesIndex = 0; + for ( String spdxFileName : SpdxFileNames ) + { + if ( spdxFileName.endsWith( ".bin" ) ) + { + continue; + } + assertEquals( spdxFileName, SpdxFiles[SpdxFilesIndex++].getName().get() ); + } + } + + @Test + public void testGetExtension() throws InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + File noExtension = new File( "noextension" ); + String result = collector.getExtension( noExtension ); + assertTrue( result.isEmpty() ); + String ext = "abcd"; + File abcd = new File( "fileName" + "." + ext ); + result = collector.getExtension( abcd ); + assertEquals( ext, result ); + File startsWithDot = new File( ".configfile" ); + result = collector.getExtension( startsWithDot ); + assertTrue( result.isEmpty() ); + File multipleDots = new File( "file.with.more.dots." + ext ); + result = collector.getExtension( multipleDots ); + assertEquals( ext, result ); + } + + @Test + public void testGetFiles() throws SpdxCollectionException, InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( 0, SpdxFiles.length ); + + collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, + new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( filePaths.length, SpdxFiles.length ); + Arrays.sort( SpdxFiles, elementComparer ); + @SuppressWarnings( "unchecked" ) + List allRelationships = (List)SpdxModelFactory + .getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.CORE_RELATIONSHIP, + null, spdxDoc.getIdPrefix() ).collect( Collectors.toList() ); + for ( int i = 0; i < SpdxFiles.length; i++ ) + { + assertEquals( SpdxFileNames[i], SpdxFiles[i].getName().get() ); + assertTrue( SpdxFiles[i].getComment().get().startsWith( DEFAULT_COMMENT ) ); + assertEquals( DEFAULT_CONTRIBUTORS.length, SpdxFiles[i].getOriginatedBys().size() ); + List contributors = new ArrayList<>(); + SpdxFiles[i].getOriginatedBys().spliterator().forEachRemaining( agent -> { + try + { + contributors.add( agent.getName().get() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + fail( "SPDX Exception getting agent name "); + } + } ); + assertArrayEquals( DEFAULT_CONTRIBUTORS, TestUtils.toSortedArray( contributors ) ); + assertEquals( DEFAULT_COPYRIGHT, SpdxFiles[i].getCopyrightText().get() ); + AnyLicenseInfo declaredLicense = null; + AnyLicenseInfo concludedLicense = null; + for ( Relationship relationship : allRelationships ) + { + if ( SpdxFiles[i].equals( relationship.getFrom() )) + { + if ( RelationshipType.HAS_CONCLUDED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + concludedLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } else if ( RelationshipType.HAS_DECLARED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + declaredLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } + } + } + if ( SpdxFileNames[i].endsWith( FILE_NAME_WITH_ID ) ) + { + assertEquals(LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS_DECLARED_LICENSE ), declaredLicense ); + assertEquals( LicenseInfoFactory.parseSPDXLicenseString( FILE_WITH_IDS__CONCLUDED_LICENSE ), concludedLicense ); + } + else + { + assertEquals( DEFAULT_DECLARED_LICENSE, declaredLicense.toString() ); + assertTrue( SpdxFiles[i].getComment().get().endsWith( DEFAULT_LICENSE_COMMENT ) ); + assertEquals( DEFAULT_CONCLUDED_LICENSE, concludedLicense.toString() ); + } + assertEquals( 1, SpdxFiles[i].getAttributionTexts().size() ); + assertEquals( DEFAULT_NOTICE, SpdxFiles[i].getAttributionTexts().iterator().next() ); + } + } + + @Test + public void testGetSnippets() throws SpdxCollectionException, InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + List snippets = collector.getSnippets(); + assertEquals( 0, snippets.size() ); + + collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, + new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + snippets = collector.getSnippets(); + assertEquals( filePaths.length, snippets.size() ); + @SuppressWarnings( "unchecked" ) + List allRelationships = (List)SpdxModelFactory + .getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.CORE_RELATIONSHIP, + null, spdxDoc.getIdPrefix() ).collect( Collectors.toList() ); + for ( Snippet snippet : snippets ) + { + AnyLicenseInfo declaredLicense = null; + AnyLicenseInfo concludedLicense = null; + for ( Relationship relationship : allRelationships ) + { + if ( snippet.equals( relationship.getFrom() )) + { + if ( RelationshipType.HAS_CONCLUDED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + concludedLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } else if ( RelationshipType.HAS_DECLARED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + declaredLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } + } + } + assertEquals( SNIPPET_NAMES, snippet.getName().get() ); + assertTrue( snippet.getComment().get().startsWith( DEFAULT_SNIPPET_COMMENT ) ); + assertEquals( DEFAULT_SNIPPET_CONCLUDED_LICENSE, concludedLicense.toString() ); + assertEquals( DEFAULT_SNIPPET_COPYRIGHT, snippet.getCopyrightText().get() ); + assertEquals( DEFAULT_SNIPPET_DECLARED_LICENSE, declaredLicense.toString() ); + assertTrue( snippet.getComment().get().endsWith( DEFAULT_SNIPPET_LICENSE_COMMENT ) ); + assertEquals( DEFAULT_SNIPPET_BYTE_RANGE, positiveIntegerRangeToString( snippet.getByteRange().get() ) ); + assertEquals( DEFAULT_SNIPPET_LINE_RANGE, positiveIntegerRangeToString( snippet.getLineRange().get() ) ); + } + } + + + public static String positiveIntegerRangeToString( PositiveIntegerRange range ) throws InvalidSPDXAnalysisException + { + return Integer.toString( range.getBeginIntegerRange() ) + ":" + Integer.toString( range.getEndIntegerRange() ); + } + + @Test + public void testCollectFilesWithPattern() throws SpdxCollectionException, InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + SpdxFile[] SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( 0, SpdxFiles.length ); + HashMap fileSpecificInfo = new HashMap<>(); + SpdxDefaultFileInformation file2Info = new SpdxDefaultFileInformation(); + String file2Comment = "File 2 comment"; + file2Info.setComment( file2Comment ); + String file2License = defaultFileInformation.getDeclaredLicense(); + file2Info.setConcludedLicense( file2License ); + String[] file2Contributors = new String[] {"Person: File 2 contributor"}; + file2Info.setContributors( file2Contributors ); + String file2Copyright = "File 2 copyright"; + file2Info.setCopyright( file2Copyright ); + String file2DeclaredLicense = defaultFileInformation.getConcludedLicense(); + file2Info.setDeclaredLicense( file2DeclaredLicense ); + String file2LicenseComment = "File 2 license comment"; + file2Info.setLicenseComment( file2LicenseComment ); + String file2Notice = "file 2 notice"; + file2Info.setNotice( file2Notice ); + fileSpecificInfo.put( + filePaths[1].substring( this.directory.getAbsolutePath().length() + 1 ).replace( '\\', '/' ), + file2Info ); + + SpdxDefaultFileInformation file3Info = new SpdxDefaultFileInformation(); + String file3Comment = "File 3 comment"; + file3Info.setComment( file3Comment ); + String file3License = defaultFileInformation.getDeclaredLicense(); + file3Info.setConcludedLicense( file3License ); + String[] file3Contributors = new String[] {"Person: File 3 contributor"}; + file3Info.setContributors( file3Contributors ); + String file3Copyright = "File 3 copyright"; + file3Info.setCopyright( file3Copyright ); + String file3DeclaredLicense = defaultFileInformation.getDeclaredLicense(); + file3Info.setDeclaredLicense( file3DeclaredLicense ); + String file3LicenseComment = "File 3 license comment"; + file3Info.setLicenseComment( file3LicenseComment ); + String file3Notice = "file 3 notice"; + file3Info.setNotice( file3Notice ); + fileSpecificInfo.put( SUB_DIRS[0], file3Info ); + + //TODO: Test directory patterns + collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, + fileSpecificInfo, spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + SpdxFiles = collector.getFiles().toArray( new SpdxFile[collector.getFiles().size()] ); + assertEquals( filePaths.length, SpdxFiles.length ); + Arrays.sort( SpdxFiles, elementComparer ); + String subDirAPrefix = "./" + directory.getName() + "/" + SUB_DIRS[0]; + + @SuppressWarnings( "unchecked" ) + List allRelationships = (List)SpdxModelFactory + .getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.CORE_RELATIONSHIP, + null, spdxDoc.getIdPrefix() ).collect( Collectors.toList() ); + for ( int i = 0; i < SpdxFiles.length; i++ ) + { + AnyLicenseInfo declaredLicense = null; + AnyLicenseInfo concludedLicense = null; + for ( Relationship relationship : allRelationships ) + { + if ( SpdxFiles[i].equals( relationship.getFrom() )) + { + if ( RelationshipType.HAS_CONCLUDED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + concludedLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } else if ( RelationshipType.HAS_DECLARED_LICENSE.equals( relationship.getRelationshipType() ) ) + { + assertEquals( 1, relationship.getTos().size() ); + declaredLicense = (AnyLicenseInfo) relationship.getTos().iterator().next(); + } + } + } + List contributors = new ArrayList<>(); + SpdxFiles[i].getOriginatedBys().spliterator().forEachRemaining( agent -> { + try + { + contributors.add( agent.getName().get() ); + } + catch ( InvalidSPDXAnalysisException e ) + { + fail( "SPDX Exception getting agent name "); + } + } ); + assertEquals( SpdxFileNames[i], SpdxFiles[i].getName().get() ); + if ( SpdxFiles[i].getName().get().equals( SpdxFileNames[1] ) ) + { + assertTrue( SpdxFiles[i].getComment().get().startsWith( file2Comment ) ); + assertEquals( file2License.toString(), concludedLicense.toString() ); + assertEquals( file2Contributors.length, contributors.size() ); + + assertArrayEquals( file2Contributors, TestUtils.toSortedArray( contributors ) ); + assertEquals( file2Copyright, SpdxFiles[1].getCopyrightText().get() ); + assertEquals( file2DeclaredLicense.toString(), declaredLicense.toString() ); + assertTrue( SpdxFiles[i].getComment().get().endsWith( file2LicenseComment ) ); + assertEquals( 1, SpdxFiles[i].getAttributionTexts().size() ); + assertEquals( file2Notice, SpdxFiles[i].getAttributionTexts().iterator().next() ); + } + else if ( SpdxFiles[i].getName().get().startsWith( subDirAPrefix ) ) + { + assertTrue( SpdxFiles[i].getComment().get().startsWith( file3Comment ) ); + assertEquals( file3License.toString(), concludedLicense.toString() ); + assertEquals( file3Contributors.length, contributors.size() ); + assertArrayEquals( file3Contributors, TestUtils.toSortedArray( contributors ) ); + assertEquals( file3Copyright, SpdxFiles[i].getCopyrightText().get() ); + assertEquals( file3DeclaredLicense.toString(), declaredLicense.toString() ); + assertTrue( SpdxFiles[i].getComment().get().endsWith( file3LicenseComment ) ); + assertEquals( 1, SpdxFiles[i].getAttributionTexts().size() ); + assertEquals( file3Notice, SpdxFiles[i].getAttributionTexts().iterator().next() ); + } + else if ( !SpdxFiles[i].getName().get().endsWith( FILE_NAME_WITH_ID ) ) + { + assertTrue( SpdxFiles[i].getComment().get().startsWith( DEFAULT_COMMENT ) ); + assertEquals( DEFAULT_CONCLUDED_LICENSE, concludedLicense.toString() ); + assertEquals( DEFAULT_CONTRIBUTORS.length, contributors.size() ); + assertArrayEquals( DEFAULT_CONTRIBUTORS, TestUtils.toSortedArray( contributors ) ); + assertEquals( DEFAULT_COPYRIGHT, SpdxFiles[i].getCopyrightText().get() ); + assertEquals( DEFAULT_DECLARED_LICENSE, declaredLicense.toString() ); + assertTrue( SpdxFiles[i].getComment().get().endsWith( DEFAULT_LICENSE_COMMENT ) ); + assertEquals( 1, SpdxFiles[i].getAttributionTexts().size() ); + assertEquals( DEFAULT_NOTICE, SpdxFiles[i].getAttributionTexts().iterator().next() ); + } + } + } + + @Test + public void testConvertChecksumToString() + { + byte[] cksumBytes = new byte[] {00, 01, 02, 03, 04, 05, 06, 07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1E}; + String expected = "000102030405060708090a0b0c0d1e"; + String result = SpdxV3FileCollector.convertChecksumToString( cksumBytes ); + assertEquals( expected, result ); + } + + @Test + public void testConvertFilePathToSpdxFileName() + { + String dosFilePath = "subdir\\subdir2\\file.c"; + String dosSpdxFile = "./subdir/subdir2/file.c"; + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + String result = collector.convertFilePathToSpdxFileName( dosFilePath ); + assertEquals( dosSpdxFile, result ); + + String unixFilePath = "unixFolder/subfolder/file.sh"; + String unixSpdxFile = "./unixFolder/subfolder/file.sh"; + result = collector.convertFilePathToSpdxFileName( unixFilePath ); + assertEquals( unixSpdxFile, result ); + } + + @Test + public void testGenerateChecksums() throws SpdxCollectionException, InvalidSPDXAnalysisException + { + SpdxV3FileCollector collector = new SpdxV3FileCollector( customIdMap ); + collector.collectFiles( this.fileSets, this.directory.getAbsolutePath(), this.defaultFileInformation, + new HashMap<>(), spdxPackage, RelationshipType.GENERATES, spdxDoc, sha1Algorithm ); + File spdxFile = new File( filePaths[0] ); + + Set checksumAlgorithmSet = new HashSet<>(); + checksumAlgorithmSet.add(ChecksumAlgorithm.SHA1.toString() ); + checksumAlgorithmSet.add( ChecksumAlgorithm.SHA256.toString() ); + + Set expectedChecksums = new HashSet<>(); + expectedChecksums.add( new Checksum( ChecksumAlgorithm.SHA1.toString(), "1834453c87b9188024c7b18d179eb64f95f29fcf" ) ); + expectedChecksums.add( new Checksum( ChecksumAlgorithm.SHA256.toString(), "1c94046c63f61f5dbe5c15cc6c4e34510132ab262aa266735b344d836ef8cb3c") ); + // Checksum does not override equals currently. Hence, need to compare manually + Set actualChecksums = SpdxV3FileCollector.generateChecksum( spdxFile, checksumAlgorithmSet ); + for ( Checksum expectedChecksum : expectedChecksums ) + { + boolean found = false; + for ( Checksum actualChecksum : actualChecksums ) + { + if ( expectedChecksum.getAlgorithm().equals( actualChecksum.getAlgorithm() ) ) + { + if ( expectedChecksum.getValue().equals( actualChecksum.getValue() ) ) + { + found = true; + } + else + { + fail("Expected checksum : " + expectedChecksum + "does not match actual checksum : " + actualChecksum); + } + } + } + if ( !found ) + { + fail("Expected checksum : " + expectedChecksum + "not found in actual checksums : " + actualChecksums); + } + } + } +} diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java b/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java new file mode 100644 index 0000000..60da92f --- /dev/null +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java @@ -0,0 +1,319 @@ +/* + * Copyright 2014 Source Auditor Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.spdx.maven.utils; + +import static org.junit.Assert.*; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.expandedlicensing.ConjunctiveLicenseSet; +import org.spdx.library.model.v3_0_1.expandedlicensing.CustomLicense; +import org.spdx.library.model.v3_0_1.expandedlicensing.ListedLicense; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.maven.NonStandardLicense; +import org.spdx.storage.simple.InMemSpdxStore; +import org.apache.maven.model.License; + +/** + * Unit tests for SpdxV3LicenseManager class + * + * @author Gary O'Neall + */ +public class TestSpdxV3LicenseManager +{ + private static final String TEST_SPDX_DOCUMENT_URL = "http://www.spdx.org/documents/test"; + static final String APACHE_CROSS_REF_URL2 = "http://www.apache.org/licenses/LICENSE-2.0"; + static final String APACHE_CROSS_REF_URL3 = "http://opensource.org/licenses/Apache-2.0"; + static final String APACHE_LICENSE_ID = "Apache-2.0"; + static final String APACHE_LICENSE_NAME = "Apache License 2.0"; + static final String APSL_CROSS_REF_URL = "http://www.opensource.apple.com/source/IOSerialFamily/IOSerialFamily-7/APPLE_LICENSE"; + static final String APSL_LICENSE_ID = "APSL-1.1"; + + SpdxDocument spdxDoc = null; + + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception + { + SpdxModelFactory.init(); + } + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception + { + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception + { + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); + spdxDoc = new SpdxDocument( new InMemSpdxStore(), TEST_SPDX_DOCUMENT_URL + "#DOCUMENT", new ModelCopyManager(), + true, TEST_SPDX_DOCUMENT_URL ); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception + { + spdxDoc = null; + } + + /** + * Test method for {@link org.spdx.maven.utils.SpdxV3LicenseManager#LicenseManager(org.spdx.rdfparser.SpdxDocument,boolean)}. + * + * @throws LicenseMapperException + */ + @Test + public void testLicenseManager() throws LicenseMapperException + { + @SuppressWarnings( "unused" ) + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + } + + /** + * Test method for {@link org.spdx.maven.utils.SpdxV3LicenseManager#addExtractedLicense(org.spdx.maven.NonStandardLicense)}. + * + * @throws MalformedURLException + * @throws LicenseManagerException + * @throws InvalidSPDXAnalysisException + * @throws LicenseMapperException + */ + @SuppressWarnings( "unchecked" ) + @Test + public void testAddNonStandardLicense() throws MalformedURLException, LicenseManagerException, InvalidSPDXAnalysisException, LicenseMapperException + { + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + NonStandardLicense lic = new NonStandardLicense(); + final String COMMENT = "comment"; + final String[] CROSS_REF_STR = new String[] {"http://www.licenseRef1", "http://www.licenseref2"}; + final URL[] CROSS_REF = new URL[] {new URL( CROSS_REF_STR[0] ), new URL( CROSS_REF_STR[1] )}; + final String EXTRACTED_TEXT = "extracted text"; + final String LICENSE_ID = "LicenseRef-licenseId"; + final String LICENSE_NAME = "licenseName"; + lic.setComment( COMMENT ); + lic.setCrossReference( CROSS_REF ); + lic.setExtractedText( EXTRACTED_TEXT ); + lic.setLicenseId( LICENSE_ID ); + lic.setName( LICENSE_NAME ); + + licenseManager.addExtractedLicense( lic ); + List result = (List) SpdxModelFactory.getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.EXPANDED_LICENSING_CUSTOM_LICENSE, + null, TEST_SPDX_DOCUMENT_URL ) + .collect( Collectors.toList() ); + assertEquals( 1, result.size() ); + assertEquals( COMMENT, result.get( 0 ).getComment().get() ); + assertArrayEquals( CROSS_REF_STR, TestUtils.toSortedArray( result.get( 0 ).getSeeAlsos() ) ); + assertEquals( EXTRACTED_TEXT, result.get( 0 ).getLicenseText() ); + assertEquals( spdxDoc.getIdPrefix() + LICENSE_ID, result.get( 0 ).getObjectUri() ); + assertEquals( LICENSE_NAME, result.get( 0 ).getName().get() ); + + NonStandardLicense lic2 = new NonStandardLicense(); + final String LICENSE_ID2 = "LicenseRef-licenseId2"; + final String EXTRACTED_TEXT2 = "Second extracted text"; + lic2.setLicenseId( LICENSE_ID2 ); + lic2.setExtractedText( EXTRACTED_TEXT2 ); + + licenseManager.addExtractedLicense( lic2 ); + + result = (List) SpdxModelFactory.getSpdxObjects( spdxDoc.getModelStore(), + spdxDoc.getCopyManager(), + SpdxConstantsV3.EXPANDED_LICENSING_CUSTOM_LICENSE, + null, TEST_SPDX_DOCUMENT_URL ) + .collect( Collectors.toList() );assertEquals( 2, result.size() ); + CustomLicense licResult = result.get( 1 ); + if ( !licResult.getObjectUri().endsWith( LICENSE_ID2 ) ) + { + licResult = result.get( 0 ); + } + assertEquals( EXTRACTED_TEXT2, licResult.getLicenseText() ); + assertEquals( spdxDoc.getIdPrefix() + LICENSE_ID2, licResult.getObjectUri() ); + + } + + /** + * Test method for {@link org.spdx.maven.utils.SpdxV3LicenseManager#mavenLicenseListToSpdxLicense(java.util.List)}. + * + * @throws LicenseManagerException + * @throws LicenseMapperException + * @throws InvalidSPDXAnalysisException + */ + @Test + public void testMavenLicenseListToSpdxLicense() throws LicenseManagerException, LicenseMapperException, InvalidSPDXAnalysisException + { + final String LICENSE1_NAME = "Apachelicense1"; + final String LICENSE2_NAME = "APSLlicense2"; + + License apache = new License(); + apache.setName( LICENSE1_NAME ); + apache.setUrl( APACHE_CROSS_REF_URL2 ); + License apsl = new License(); + apsl.setName( LICENSE2_NAME ); + apsl.setUrl( APSL_CROSS_REF_URL ); + + ArrayList licenseList = new ArrayList<>(); + licenseList.add( apache ); + licenseList.add( apsl ); + + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, true ); + + AnyLicenseInfo result = licenseManager.mavenLicenseListToSpdxLicense( licenseList ); + assertTrue( result instanceof ConjunctiveLicenseSet ); + Collection members = ( (ConjunctiveLicenseSet) result ).getMembers(); + AnyLicenseInfo[] resultLicenses = members.toArray( new AnyLicenseInfo[members.size()] ); + assertEquals( 2, resultLicenses.length ); + assertTrue( resultLicenses[0] instanceof ListedLicense ); + if ( !( (ListedLicense) resultLicenses[0] ).getObjectUri().endsWith( + APACHE_LICENSE_ID ) && !( (ListedLicense) resultLicenses[0] ).getObjectUri().endsWith( + APSL_LICENSE_ID ) ) + { + fail( "Unrecognized first license " + ( (ListedLicense) resultLicenses[0] ).getObjectUri() ); + } + assertTrue( resultLicenses[1] instanceof ListedLicense ); + if ( !( (ListedLicense) resultLicenses[1] ).getObjectUri().endsWith( + APACHE_LICENSE_ID ) && !( (ListedLicense) resultLicenses[1] ).getObjectUri().endsWith( + APSL_LICENSE_ID ) ) + { + fail( "Unrecognized second license " + ( (ListedLicense) resultLicenses[1] ).getObjectUri() ); + } + } + + /** + * Test method for {@link org.spdx.maven.utils.SpdxV3LicenseManager#mavenLicenseToSpdxLicense(org.apache.maven.model.License)}. + * + * @throws LicenseManagerException + * @throws MalformedURLException + * @throws LicenseMapperException + * @throws InvalidSPDXAnalysisException + */ + @Test + public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, MalformedURLException, LicenseMapperException, InvalidSPDXAnalysisException + { + // unmapped license - can not test without valid log + // standard license + final String LICENSE1_NAME = "Apachelicense1"; + License apache = new License(); + apache.setName( LICENSE1_NAME ); + apache.setUrl( APACHE_CROSS_REF_URL2 ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, true ); + + AnyLicenseInfo result = licenseManager.mavenLicenseToSpdxLicense( apache ); + assertTrue( result instanceof ListedLicense ); + assertEquals( SpdxConstantsV3.SPDX_LISTED_LICENSE_NAMESPACE + APACHE_LICENSE_ID, ( (ListedLicense) result ).getObjectUri() ); + + // nonstandard license + NonStandardLicense lic = new NonStandardLicense(); + final String COMMENT = "comment"; + final String[] CROSS_REF_STR = new String[] {"http://www.licenseRef1"}; + final URL[] CROSS_REF = new URL[] {new URL( CROSS_REF_STR[0] )}; + final String EXTRACTED_TEXT = "extracted text"; + final String LICENSE_ID = "LicenseRef-licenseId"; + final String LICENSE_NAME = "licenseName"; + lic.setComment( COMMENT ); + lic.setCrossReference( CROSS_REF ); + lic.setExtractedText( EXTRACTED_TEXT ); + lic.setLicenseId( LICENSE_ID ); + lic.setName( LICENSE_NAME ); + licenseManager.addExtractedLicense( lic ); + License nonStd = new License(); + nonStd.setComments( COMMENT ); + nonStd.setName( LICENSE_NAME ); + nonStd.setUrl( CROSS_REF_STR[0] ); + result = licenseManager.mavenLicenseToSpdxLicense( nonStd ); + + assertTrue( result instanceof CustomLicense ); + CustomLicense nonStdResult = (CustomLicense) result; + assertEquals( COMMENT, nonStdResult.getComment().get() ); + assertArrayEquals( CROSS_REF_STR, TestUtils.toSortedArray( nonStdResult.getSeeAlsos() ) ); + assertEquals( EXTRACTED_TEXT, nonStdResult.getLicenseText() ); + assertEquals( spdxDoc.getIdPrefix() + LICENSE_ID, nonStdResult.getObjectUri() ); + assertEquals( LICENSE_NAME, nonStdResult.getName().get() ); + } + + /** + * Test method for {@link org.spdx.maven.utils.SpdxV3LicenseManager#spdxLicenseToMavenLicense(org.spdx.rdfparser.AnyLicenseInfo)}. + * + * @throws LicenseManagerException + * @throws LicenseMapperException + * @throws InvalidSPDXAnalysisException + */ + @Test + public void testSpdxLicenseToMavenLicense() throws LicenseManagerException, LicenseMapperException, InvalidSPDXAnalysisException + { + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + // standard license + AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseString( APACHE_LICENSE_ID ); + License result = licenseManager.spdxLicenseToMavenLicense( licenseInfo ); + assertEquals( result.getName(), ( (ListedLicense) licenseInfo ).getName().get() ); + String resultUrl = result.getUrl().replace( "https", "http" ); + assertTrue( APACHE_CROSS_REF_URL2.equals( resultUrl ) || APACHE_CROSS_REF_URL3.equals( resultUrl ) ); + + // non standard license + final String LICENSE_ID = "LicenseRef-nonStd1"; + final String LICENSE_TEXT = "License Text"; + final ArrayList CROSS_REF_URLS = new ArrayList<>(); + CROSS_REF_URLS.add( "http://nonStd.url" ); + final String LICENSE_NAME = "License Name"; + final String LICENSE_COMMENT = "License Comment"; + CustomLicense nonStd = new CustomLicense( spdxDoc.getModelStore(), spdxDoc.getIdPrefix() + LICENSE_ID, + spdxDoc.getCopyManager(), true, spdxDoc.getIdPrefix() ); + nonStd.setLicenseText( LICENSE_TEXT ); + nonStd.getSeeAlsos().addAll( CROSS_REF_URLS ); + nonStd.setName( LICENSE_NAME ); + nonStd.setComment( LICENSE_COMMENT ); + result = licenseManager.spdxLicenseToMavenLicense( nonStd ); + assertEquals( LICENSE_NAME, result.getName() ); + assertEquals( CROSS_REF_URLS.get( 0 ), result.getUrl() ); + + // non-standard without name + final String LICENSE_ID2 = "LicenseRef-second"; + final String LICENSE_TEXT2 = "second text"; + CustomLicense noName = new CustomLicense( spdxDoc.getModelStore(), spdxDoc.getIdPrefix() + LICENSE_ID2, + spdxDoc.getCopyManager(), true, spdxDoc.getIdPrefix() ); + noName.setLicenseText( LICENSE_TEXT2 ); + result = licenseManager.spdxLicenseToMavenLicense( noName ); + assertEquals( LICENSE_ID2, result.getName() ); + } +} From 414f6bb69484d59e3d4feeda2688a89dacde09e0 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Wed, 13 Nov 2024 14:53:53 -0800 Subject: [PATCH 05/10] Generates SPDX V3 files - passes unit tests --- pom.xml | 2 +- .../utils/AbstractDependencyBuilder.java | 9 +- .../maven/utils/SpdxV3DocumentBuilder.java | 29 +- .../java/org/spdx/maven/TestSpdxV3Mojo.java | 474 ++++++++++++++++++ .../spdx/maven/TestWithSessionSpdxV3Mojo.java | 209 ++++++++ .../json-pom-dependencies-v3.xml | 107 ++++ .../unit/spdx-maven-plugin-test/pom-v3.xml | 243 +++++++++ 7 files changed, 1058 insertions(+), 15 deletions(-) create mode 100644 src/test/java/org/spdx/maven/TestSpdxV3Mojo.java create mode 100644 src/test/java/org/spdx/maven/TestWithSessionSpdxV3Mojo.java create mode 100644 src/test/resources/unit/spdx-maven-plugin-test/json-pom-dependencies-v3.xml create mode 100644 src/test/resources/unit/spdx-maven-plugin-test/pom-v3.xml diff --git a/pom.xml b/pom.xml index 12ae396..79e8032 100644 --- a/pom.xml +++ b/pom.xml @@ -150,7 +150,7 @@ org.spdx spdx-v3jsonld-store - 0.1.0-Alpha + 0.1.1-SNAPSHOT diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java index a667ea8..fee8344 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java @@ -8,6 +8,9 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; +import java.util.Objects; + +import javax.annotation.Nullable; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; @@ -93,8 +96,12 @@ abstract void addMavenDependency( CoreModelObject parentPackage, DependencyNode * @param versionFilter Optional (nullable) version - if present, only return file formats that support the filter version * @return SPDX file using the SPDX naming conventions if it exists, otherwise return null */ - protected File artifactFileToSpdxFile( File file, SpdxMajorVersion versionFilter ) + protected @Nullable File artifactFileToSpdxFile( @Nullable File file, @Nullable SpdxMajorVersion versionFilter ) { + if ( Objects.isNull( file ) ) + { + return null; + } for ( OutputFormat of: OutputFormat.values() ) { if ( versionFilter == null || versionFilter.equals( of.getSpecVersion() )) diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index 9778730..0475b81 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -29,7 +29,6 @@ import org.spdx.library.model.v2.enumerations.ChecksumAlgorithm; import org.spdx.library.model.v2.enumerations.ReferenceCategory; import org.spdx.library.model.v3_0_1.SpdxConstantsV3; -import org.spdx.library.model.v3_0_1.SpdxModelClassFactoryV3; import org.spdx.library.model.v3_0_1.core.AnnotationType; import org.spdx.library.model.v3_0_1.core.CreationInfo; import org.spdx.library.model.v3_0_1.core.DictionaryEntry; @@ -39,6 +38,7 @@ import org.spdx.library.model.v3_0_1.core.RelationshipCompleteness; import org.spdx.library.model.v3_0_1.core.RelationshipType; import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.core.Tool; import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; import org.spdx.library.model.v3_0_1.software.Sbom; import org.spdx.library.model.v3_0_1.software.SoftwareArtifact; @@ -103,16 +103,7 @@ public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, try { modelStore = new JsonLDStore( new InMemSpdxStore() ); - String supplier = ( mavenProject.getOrganization() != null && - mavenProject.getOrganization().getName() != null - && !mavenProject.getOrganization().getName().isEmpty() ) ? mavenProject.getOrganization().getName() : project.getName() ; - - creationInfo = SpdxModelClassFactoryV3.createCreationInfo( modelStore, namespaceUri + "Agent/supplier", supplier, - copyManager); - creationInfo.getCreatedUsings().add( creationInfo.createTool( namespaceUri + "Agent/SpdxMavenPlugin" ) - .setName( "SPDX Maven Plugin" ) - .setCreationInfo( creationInfo ) - .build() ); + creationInfo = new CreationInfo( modelStore, modelStore.getNextId( IdType.Anonymous ), copyManager, true, namespaceUri.toString() ); sbom = creationInfo.createSbom( namespaceUri + "sbom" ).build(); spdxDoc = sbom.createSpdxDocument( namespaceUri + "/Document" ) .addRootElement( sbom ) @@ -198,6 +189,7 @@ private void addSpdxAnnotations( org.spdx.maven.Annotation[] annotations, Elemen .setCreated( annotation.getAnnotationDate() ) .setSpecVersion( SpdxConstantsV3.MODEL_SPEC_VERSION ) .build(); + creationInfo.setIdPrefix( element.getIdPrefix() ); creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( annotation.getAnnotator(), creationInfo ) ); element.createAnnotation( element.getIdPrefix() + element.getModelStore().getNextId( IdType.SpdxId ) ) .setAnnotationType( annotationType ) @@ -227,7 +219,17 @@ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws { try { - creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( parameterCreator, creationInfo ) ); + if ( parameterCreator.startsWith( "Tool:" )) + { + Tool tool = spdxDoc.createTool( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) + .setName( parameterCreator.substring( "Tool:".length() ).trim() ) + .build(); + creationInfo.getCreatedUsings().add( tool ); + } + else + { + creationInfo.getCreatedBys().add( Spdx2to3Converter.stringToAgent( parameterCreator, creationInfo ) ); + } } catch (InvalidSPDXAnalysisException e) { @@ -458,7 +460,8 @@ private void addExternalRefs( ExternalReference[] externalRefs, SoftwareArtifact } try { - Spdx2to3Converter.addExternalRefToArtifact( cat, refType, externalRef.getLocator(), artifact, artifact.getModelStore() ); + Spdx2to3Converter.addExternalRefToArtifact( cat, refType, externalRef.getLocator(), externalRef.getComment(), + artifact, artifact.getModelStore() ); } catch ( InvalidSPDXAnalysisException e ) { diff --git a/src/test/java/org/spdx/maven/TestSpdxV3Mojo.java b/src/test/java/org/spdx/maven/TestSpdxV3Mojo.java new file mode 100644 index 0000000..674b0fa --- /dev/null +++ b/src/test/java/org/spdx/maven/TestSpdxV3Mojo.java @@ -0,0 +1,474 @@ +package org.spdx.maven; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.spdx.core.DefaultModelStore; +import org.spdx.library.LicenseInfoFactory; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; +import org.spdx.library.model.v3_0_1.core.Agent; +import org.spdx.library.model.v3_0_1.core.AnnotationType; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.core.ExternalIdentifier; +import org.spdx.library.model.v3_0_1.core.ExternalIdentifierType; +import org.spdx.library.model.v3_0_1.core.ExternalRef; +import org.spdx.library.model.v3_0_1.core.ExternalRefType; +import org.spdx.library.model.v3_0_1.core.Organization; +import org.spdx.library.model.v3_0_1.core.Person; +import org.spdx.library.model.v3_0_1.core.Relationship; +import org.spdx.library.model.v3_0_1.core.RelationshipType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.expandedlicensing.CustomLicense; +import org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo; +import org.spdx.library.model.v3_0_1.software.Sbom; +import org.spdx.library.model.v3_0_1.software.Snippet; +import org.spdx.library.model.v3_0_1.software.SpdxFile; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.maven.utils.TestSpdxV3FileCollector; +import org.spdx.storage.ISerializableModelStore; +import org.spdx.storage.simple.InMemSpdxStore; +import org.spdx.v3jsonldstore.JsonLDStore; + +public class TestSpdxV3Mojo extends AbstractMojoTestCase +{ + + private static final String UNIT_TEST_RESOURCE_DIR = "target/test-classes/unit/spdx-maven-plugin-test"; + private static final String SPDX_FILE_NAME = UNIT_TEST_RESOURCE_DIR + "/test.json-ld.json"; + + @AfterClass + public static void tearDownAfterClass() throws Exception + { + } + + @Before + protected void setUp() throws Exception + { + super.setUp(); + SpdxModelFactory.init(); + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); + } + + @After + protected void tearDown() throws Exception + { + super.tearDown(); + } + + @SuppressWarnings( "unchecked" ) + @Test + public void testExecute() throws Exception + { + File testPom = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/pom-v3.xml" ); + // CreateSpdxMojo mojo = (CreateSpdxMojo) configureMojo( myMojo, "spdx-maven-plugin", testPom ); + // if the below does not work due to a lookup error, run mvn test goal + CreateSpdxMojo mojo = (CreateSpdxMojo) lookupMojo( "createSPDX", testPom ); + assertNotNull( mojo ); + mojo.execute(); + // Test SPDX filename parameter + File spdxFile = new File( getBasedir(), SPDX_FILE_NAME ); + assertTrue( spdxFile.exists() ); + // Test output artifact file is created + File artifactFile = getTestFile( + "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.json-ld.json" ); + assertTrue( artifactFile.exists() ); + ISerializableModelStore modelStore = new JsonLDStore( new InMemSpdxStore() ); + ModelCopyManager copyManager = new ModelCopyManager(); + SpdxDocument result; + try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) + { + result = (SpdxDocument)modelStore.deSerialize( is, false ); + } + List warnings = result.verify(); + assertEquals( 0, warnings.size() ); + // Test configuration parameters found in the test resources pom.xml file + // Non-standard licenses + List customLicenses = (List)SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsV3.EXPANDED_LICENSING_CUSTOM_LICENSE, + null, result.getIdPrefix() ).collect( Collectors.toList() ); + assertEquals( 2, customLicenses.size() ); + CustomLicense testLicense1 = null; + CustomLicense testLicense2 = null; + for ( CustomLicense li : customLicenses ) + { + if ( li.getObjectUri().endsWith( "LicenseRef-testLicense" ) ) + { + testLicense1 = li; + } + else if ( li.getObjectUri().endsWith( "LicenseRef-testLicense2" ) ) + { + testLicense2 = li; + } + } + assertTrue( testLicense1 != null ); + assertEquals( "Test License", testLicense1.getName().get() ); + assertEquals( "Test license text", testLicense1.getLicenseText() ); + assertEquals( 1, testLicense1.getSeeAlsos().size() ); + assertEquals( "http://www.test.url/testLicense.html", testLicense1.getSeeAlsos().toArray( new String[testLicense1.getSeeAlsos().size()] )[0] ); + assertEquals( "Test license comment", testLicense1.getComment().get() ); + + assertTrue( testLicense2 != null ); + assertEquals( "Second Test License", testLicense2.getName().get() ); + assertEquals( "Second est license text", testLicense2.getLicenseText() ); + assertEquals( 2, testLicense2.getSeeAlsos().size() ); + boolean foundSeeAlso1 = false; + boolean foundSeeAlso2 = false; + for ( String seeAlso : testLicense2.getSeeAlsos() ) + { + if ( seeAlso.equals( "http://www.test.url/testLicense2.html" ) ) + { + foundSeeAlso1 = true; + } + else if ( seeAlso.equals( "http://www.test.url/testLicense2-alt.html" ) ) + { + foundSeeAlso2 = true; + } + } + assertTrue( foundSeeAlso1 ); + assertTrue( foundSeeAlso2 ); + assertEquals( "Second Test license comment", testLicense2.getComment().get() ); + // documentComment + assertEquals( "Document Comment", result.getComment().get() ); + // documentAnnotations + List allAnnotations = (List)SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsV3.CORE_ANNOTATION, + null, result.getIdPrefix() ).collect( Collectors.toList() ); + int numDocAnnotations = 0; + org.spdx.library.model.v3_0_1.core.Annotation annotation1 = null; + org.spdx.library.model.v3_0_1.core.Annotation annotation2 = null; + for ( org.spdx.library.model.v3_0_1.core.Annotation annotation : allAnnotations ) + { + if ( annotation.getSubject().equals( result ) ) + { + numDocAnnotations++; + if ( annotation.getStatement().get().equals( "Annotation1" ) ) + { + annotation1 = annotation; + } + else if ( annotation.getStatement().get().equals( "Annotation2" ) ) + { + annotation2 = annotation; + } + } + } + assertEquals( 2, numDocAnnotations ); + + assertTrue( annotation1 != null ); + assertEquals( "2010-01-29T18:30:22Z", annotation1.getCreationInfo().getCreated() ); + Collection annotators = annotation1.getCreationInfo().getCreatedBys(); + assertEquals( 1, annotators.size() ); + assertEquals( "Test Person", annotators.iterator().next().getName().get() ); + assertEquals( AnnotationType.REVIEW, annotation1.getAnnotationType() ); + + assertTrue( annotation2 != null ); + annotators = annotation2.getCreationInfo().getCreatedBys(); + assertEquals( 1, annotators.size() ); + assertEquals( "2012-11-29T18:30:22Z", annotation2.getCreationInfo().getCreated() ); + assertEquals( "Test Organization", annotators.iterator().next().getName().get() ); + assertEquals( AnnotationType.OTHER, annotation2.getAnnotationType() ); + //creatorComment + assertEquals( "Creator comment", result.getCreationInfo().getComment().get() ); + // creators + assertEquals( 2, result.getCreationInfo().getCreatedBys().size() ); + boolean foundCreator1 = false; + boolean foundCreator2 = false; + for ( Agent creator : result.getCreationInfo().getCreatedBys() ) + { + if ( creator instanceof Person && creator.getName().get().equals( "Creator1" ) ) + { + foundCreator1 = true; + } + else if ( creator instanceof Person && creator.getName().get().equals( "Creator2" ) ) + { + foundCreator2 = true; + } + } + assertTrue( foundCreator1 ); + assertTrue( foundCreator2 ); + assertEquals( 1, result.getCreationInfo().getCreatedUsings().size() ); + assertEquals( "spdx-maven-plugin", result.getCreationInfo().getCreatedUsings().iterator().next().getName().get() ); + // package parameters + assertEquals( 1, result.getRootElements().size() ); + Element sbom = result.getRootElements().toArray( new Element[result.getRootElements().size()] )[0]; + assertTrue( sbom instanceof Sbom ); + assertEquals(1, ((Sbom)sbom).getRootElements().size() ); + Element described = ((Sbom)sbom).getRootElements().iterator().next(); + assertTrue( described instanceof SpdxPackage ); + SpdxPackage pkg = (SpdxPackage) described; + // packageAnnotations + int numPkgAnnotations = 0; + org.spdx.library.model.v3_0_1.core.Annotation pkgAnnotation = null; + + for ( org.spdx.library.model.v3_0_1.core.Annotation annotation : allAnnotations ) + { + if ( annotation.getSubject().equals( pkg ) ) + { + numPkgAnnotations++; + pkgAnnotation = annotation; + } + } + assertEquals( 1, numPkgAnnotations ); + assertEquals( "PackageAnnotation", pkgAnnotation.getStatement().get() ); + assertEquals( "2015-01-29T18:30:22Z", pkgAnnotation.getCreationInfo().getCreated() ); + annotators = pkgAnnotation.getCreationInfo().getCreatedBys(); + assertEquals( 1, annotators.size() ); + Agent annotator = annotators.iterator().next(); + assertTrue( annotator instanceof Person ); + assertEquals( "Test Package Person", annotator.getName().get() ); + assertEquals( AnnotationType.REVIEW, pkgAnnotation.getAnnotationType() ); + List allRelationships = (List)SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsV3.CORE_RELATIONSHIP, + null, result.getIdPrefix() ).collect( Collectors.toList() ); + AnyLicenseInfo pkgLicenseDeclared = null; + AnyLicenseInfo pkgLicenseConcluded = null; + + for ( Relationship relationship : allRelationships ) + { + if ( relationship.getFrom().equals( pkg ) ) + { + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_DECLARED_LICENSE )) + { + assertTrue( pkgLicenseDeclared == null ); + assertEquals( 1, relationship.getTos().size() ); + pkgLicenseDeclared = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_CONCLUDED_LICENSE )) + { + assertTrue( pkgLicenseConcluded == null ); + assertEquals( 1, relationship.getTos().size() ); + pkgLicenseConcluded = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + } + } + //licenseDeclared + AnyLicenseInfo licenseDeclared = LicenseInfoFactory.getListedLicenseById( "BSD-2-Clause" ); + assertEquals( licenseDeclared, pkgLicenseDeclared ); + //licenseConcluded + AnyLicenseInfo licenseConcluded = LicenseInfoFactory.getListedLicenseById( "BSD-3-Clause" ); + assertEquals( licenseConcluded, pkgLicenseConcluded ); + //licenseComments + assertTrue( pkg.getComment().get().endsWith( "License comments" ) ); + //originator + assertEquals( 1, pkg.getOriginatedBys().size() ); + Agent originator = pkg.getOriginatedBys().iterator().next(); + assertTrue( originator instanceof Organization ); + assertEquals( "Originating org.", originator.getName().get() ); + // sourceInfo + assertEquals( "Source info", pkg.getSourceInfo().get() ); + //copyrightText + assertEquals( "Copyright Text for Package", pkg.getCopyrightText().get() ); + //external Refs + ExternalRef[] externalRefs = pkg.getExternalRefs().toArray( new ExternalRef[pkg.getExternalRefs().size()] ); + assertEquals( 1, externalRefs.length ); + assertEquals( ExternalRefType.MAVEN_CENTRAL, externalRefs[0].getExternalRefType().get() ); + assertEquals( "extref comment2", externalRefs[0].getComment().get() ); + assertEquals( 1, externalRefs[0].getLocators().size() ); + assertEquals( "org.apache.tomcat:tomcat:9.0.0.M4", externalRefs[0].getLocators().iterator().next() ); + ExternalIdentifier[] externalIds = pkg.getExternalIdentifiers().toArray( new ExternalIdentifier[pkg.getExternalIdentifiers().size()] ); + assertEquals( 1, externalIds.length ); + assertEquals( ExternalIdentifierType.CPE22, externalIds[0].getExternalIdentifierType() ); + assertEquals( "extref comment1", externalIds[0].getComment().get() ); + assertEquals( "example-locator-CPE22Type", externalIds[0].getIdentifier() ); + + // Test all files are included + List filePaths = new ArrayList<>(); + File sourceDir = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/src/main" ); + addFilePaths( getBasedir() + UNIT_TEST_RESOURCE_DIR, sourceDir, filePaths ); + File testDir = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/src/test" ); + addFilePaths( getBasedir() + UNIT_TEST_RESOURCE_DIR, testDir, filePaths ); + @SuppressWarnings( "unused" ) + File resourceDir = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/src/resources" ); + //TODO: Add resource to project stub and uncomment the line below + // addFilePaths( getBasedir() + UNIT_TEST_RESOURCE_DIR, resourceDir, filePaths ); + List pkgFiles = new ArrayList<>(); + for ( Relationship relationship : allRelationships ) + { + if ( relationship.getFrom().equals( pkg ) ) + { + if ( relationship.getRelationshipType().equals( RelationshipType.CONTAINS )) + { + for ( Element to : relationship.getTos() ) + { + if ( to instanceof SpdxFile ) + { + pkgFiles.add( (SpdxFile)to ); + } + } + } + } + } + assertEquals( filePaths.size(), pkgFiles.size() ); + String fileWithSnippet = null; + for ( SpdxFile sFile : pkgFiles ) + { + AnyLicenseInfo fileLicenseConcluded = null; + AnyLicenseInfo fileLicenseDeclared = null; + for ( Relationship relationship : allRelationships ) + { + if ( relationship.getFrom().equals( sFile ) ) + { + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_DECLARED_LICENSE )) + { + assertTrue( fileLicenseDeclared == null ); + assertEquals( 1, relationship.getTos().size() ); + fileLicenseDeclared = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_CONCLUDED_LICENSE )) + { + assertTrue( fileLicenseConcluded == null ); + assertEquals( 1, relationship.getTos().size() ); + fileLicenseConcluded = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + } + } + if ( sFile.getName().get().equals( "./src/main/java/CommonCode.java" ) ) + { + fileWithSnippet = sFile.getObjectUri(); + assertTrue( sFile.getComment().get().startsWith( "Comment for CommonCode" ) ); + assertEquals( "Common Code Copyright", sFile.getCopyrightText().get() ); + assertTrue( sFile.getComment().get().endsWith( "License Comment for Common Code" ) ); + assertEquals( 1, sFile.getAttributionTexts().size() ); + assertEquals( "Notice for Commmon Code", sFile.getAttributionTexts().iterator().next() ); + assertEquals( "EPL-1.0", fileLicenseConcluded.toString() ); + assertEquals( 1, sFile.getOriginatedBys().size() ); + Agent fileOriginator = sFile.getOriginatedBys().iterator().next(); + assertTrue( fileOriginator instanceof Person ); + assertEquals( "Contributor to CommonCode", fileOriginator.getName().get() ); + assertEquals( "ISC", fileLicenseDeclared.toString() ); + } + else + { + assertTrue( sFile.getComment().get().startsWith( "Default file comment" ) ); + assertEquals( "Copyright (c) 2012, 2013, 2014 Source Auditor Inc.", sFile.getCopyrightText().get() ); + assertTrue( sFile.getComment().get().endsWith( "Default file license comment" ) ); + assertEquals( 1, sFile.getAttributionTexts().size() ); + assertEquals( "Default file notice", sFile.getAttributionTexts().iterator().next() ); + assertEquals( "Apache-2.0", fileLicenseConcluded.toString() ); + assertEquals( 2, sFile.getOriginatedBys().size() ); + assertEquals( "Apache-1.1", fileLicenseDeclared.toString() ); + } + filePaths.remove( sFile.getName().get() ); + } + assertEquals( 0, filePaths.size() ); + List snippets = (List)SpdxModelFactory.getSpdxObjects( modelStore, copyManager, SpdxConstantsV3.SOFTWARE_SNIPPET, + null, result.getIdPrefix() ).collect( Collectors.toList() ); + assertEquals( 2, snippets.size() ); + Snippet snippet1; + Snippet snippet2; + if ( snippets.get( 0 ).getComment().get().startsWith( "Snippet Comment2" ) ) + { + snippet1 = snippets.get( 1 ); + snippet2 = snippets.get( 0 ); + } + else + { + snippet1 = snippets.get( 0 ); + snippet2 = snippets.get( 1 ); + } + AnyLicenseInfo snippet1LicenseConcluded = null; + AnyLicenseInfo snippet1LicenseDeclared = null; + AnyLicenseInfo snippet2LicenseConcluded = null; + AnyLicenseInfo snippet2LicenseDeclared = null; + for ( Relationship relationship : allRelationships ) + { + if ( relationship.getFrom().equals( snippet1 ) ) + { + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_DECLARED_LICENSE )) + { + assertTrue( snippet1LicenseDeclared == null ); + assertEquals( 1, relationship.getTos().size() ); + snippet1LicenseDeclared = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_CONCLUDED_LICENSE )) + { + assertTrue( snippet1LicenseConcluded == null ); + assertEquals( 1, relationship.getTos().size() ); + snippet1LicenseConcluded = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + } else if ( relationship.getFrom().equals( snippet2 ) ) + { + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_DECLARED_LICENSE )) + { + assertTrue( snippet2LicenseDeclared == null ); + assertEquals( 1, relationship.getTos().size() ); + snippet2LicenseDeclared = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + if ( relationship.getRelationshipType().equals( RelationshipType.HAS_CONCLUDED_LICENSE )) + { + assertTrue( snippet2LicenseConcluded == null ); + assertEquals( 1, relationship.getTos().size() ); + snippet2LicenseConcluded = (AnyLicenseInfo)relationship.getTos().iterator().next(); + } + } + } + assertTrue( snippet1.getComment().get().startsWith( "Snippet Comment" ) ); + assertEquals( "Snippet Copyright Text", snippet1.getCopyrightText().get() ); + assertTrue( snippet1.getComment().get().endsWith( "Snippet License Comment" ) ); + assertEquals( "SnippetName", snippet1.getName().get() ); + assertEquals( "1231:3442", TestSpdxV3FileCollector.positiveIntegerRangeToString( snippet1.getByteRange().get() ) ); + assertEquals( "BSD-2-Clause", snippet1LicenseConcluded.toString() ); + assertEquals( "BSD-2-Clause-FreeBSD", snippet1LicenseDeclared.toString() ); + assertEquals( "44:55", TestSpdxV3FileCollector.positiveIntegerRangeToString( snippet1.getLineRange().get() ) ); + assertEquals( fileWithSnippet, snippet1.getSnippetFromFile().getObjectUri() ); + + assertTrue( snippet2.getComment().get().startsWith( "Snippet Comment2" ) ); + assertEquals( "Snippet2 Copyright Text", snippet2.getCopyrightText().get() ); + assertTrue( snippet2.getComment().get().endsWith( "Snippet2 License Comment" ) ); + assertEquals( "SnippetName2", snippet2.getName().get() ); + assertEquals( "31231:33442", + TestSpdxV3FileCollector.positiveIntegerRangeToString( snippet2.getByteRange().get() ) ); + assertEquals( "MITNFA", snippet2LicenseConcluded.toString() ); + assertEquals( "LicenseRef-testLicense", snippet2LicenseDeclared.toString() ); + assertEquals( "444:554", + TestSpdxV3FileCollector.positiveIntegerRangeToString( snippet2.getLineRange().get() ) ); + assertEquals( fileWithSnippet, snippet2.getSnippetFromFile().getObjectUri() ); + //TODO Test dependencies + } + + /** + * Add relative file paths to the filePaths list + * + * @param prefix Absolute path of the directory to which the filepaths are relative + * @param dir Directory of files to add + * @param filePaths return list of file paths to which paths are added + */ + private void addFilePaths( String prefix, File dir, List filePaths ) + { + if ( !dir.exists() ) + { + return; + } + if ( !dir.isDirectory() ) + { + filePaths.add( "./" + dir.getAbsolutePath().substring( prefix.length() + 2 ).replace( '\\', '/' ) ); + return; + } + File[] files = dir.listFiles(); + for ( File file : files ) + { + if ( file.isDirectory() ) + { + addFilePaths( prefix, file, filePaths ); + } + else + { + filePaths.add( "./" + file.getAbsolutePath().substring( prefix.length() + 2 ).replace( '\\', '/' ) ); + } + } + } + + @Test + public void testmatchLicensesOnCrossReferenceUrls() + { + //TODO Implement testcase - parameter matLicensesOnCrossReferenceUrls=false + } +} diff --git a/src/test/java/org/spdx/maven/TestWithSessionSpdxV3Mojo.java b/src/test/java/org/spdx/maven/TestWithSessionSpdxV3Mojo.java new file mode 100644 index 0000000..f44572a --- /dev/null +++ b/src/test/java/org/spdx/maven/TestWithSessionSpdxV3Mojo.java @@ -0,0 +1,209 @@ +package org.spdx.maven; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; +import org.apache.maven.artifact.repository.MavenArtifactRepository; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.execution.DefaultMavenExecutionRequest; +import org.apache.maven.execution.DefaultMavenExecutionResult; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.project.ProjectBuildingRequest; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.impl.DefaultServiceLocator; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.spdx.core.DefaultModelStore; +import org.spdx.core.InvalidSPDXAnalysisException; +import org.spdx.jacksonstore.MultiFormatStore; +import org.spdx.jacksonstore.MultiFormatStore.Format; +import org.spdx.library.ModelCopyManager; +import org.spdx.library.SpdxModelFactory; +import org.spdx.library.model.v3_0_1.SpdxConstantsV3; +import org.spdx.library.model.v3_0_1.core.Element; +import org.spdx.library.model.v3_0_1.core.Relationship; +import org.spdx.library.model.v3_0_1.core.RelationshipType; +import org.spdx.library.model.v3_0_1.core.SpdxDocument; +import org.spdx.library.model.v3_0_1.software.SpdxPackage; +import org.spdx.spdxRdfStore.RdfStore; +import org.spdx.storage.ISerializableModelStore; +import org.spdx.storage.simple.InMemSpdxStore; +import org.spdx.v3jsonldstore.JsonLDStore; + +public class TestWithSessionSpdxV3Mojo extends AbstractMojoTestCase +{ + + private static final String UNIT_TEST_RESOURCE_DIR = "target/test-classes/unit/spdx-maven-plugin-test"; + + @Before + protected void setUp() throws Exception + { + super.setUp(); + SpdxModelFactory.init(); + DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager()); + } + + @After + protected void tearDown() throws Exception + { + super.tearDown(); + } + + @Test + public void testDependencies() throws Exception + { + File pom = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/json-pom-dependencies-v3.xml" ); + SpdxDocument result = runMojoWithPom( pom ); + + Set packages = new HashSet<>(); + Set relationships = new HashSet<>(); + SpdxModelFactory.getSpdxObjects( result.getModelStore(), result.getCopyManager(), SpdxConstantsV3.CORE_LIFECYCLE_SCOPED_RELATIONSHIP, + null, result.getIdPrefix() ) + .forEach( ( element ) -> { + try + { + Relationship rel = (Relationship)element; + if ( rel.getFrom() instanceof SpdxPackage ) + { + SpdxPackage pkg = (SpdxPackage)rel.getFrom(); + packages.add( pkg.getName().get() ); + for ( Element to : rel.getTos() ) + { + if ( to instanceof SpdxPackage ) + { + Optional pkgName = pkg.getName(); + Optional toName = to.getName(); + relationships.add( pkgName.get() + "->" + toName.get() ); + } + } + } + } + catch( InvalidSPDXAnalysisException e ) + { + throw new RuntimeException( e ); + } + }); + + assertTrue( packages.contains( "org.spdx:spdx-maven-plugin-test" ) ); + assertTrue( packages.contains( "junit" ) ); + assertTrue( relationships.contains( "org.spdx:spdx-maven-plugin-test->junit" ) ); + assertTrue( relationships.contains( "junit->hamcrest-core" ) || relationships.contains( "junit->org.hamcrest:hamcrest-core" ) ); + } + + // -- Configure mojo loader + + private SpdxDocument runMojoWithPom( File pom ) throws Exception + { + CreateSpdxMojo mojo = (CreateSpdxMojo) lookupConfiguredMojo( readMavenProject( pom ), "createSPDX" ); + mojo.execute(); + + File artifactFile = (File) getVariableValueFromObject( mojo, "spdxFile" ); + assertTrue( artifactFile.exists() ); + String outputFormat = (String) getVariableValueFromObject( mojo, "outputFormat" ); + ISerializableModelStore modelStore = buildModelStore( outputFormat ); + try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) + { + return (SpdxDocument)modelStore.deSerialize( is, false ); + } + } + + private ISerializableModelStore buildModelStore( String outputFormat ) + { + switch ( outputFormat ) + { + case "JSON": + return new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); + case "RDF/XML": + return new RdfStore(); + case "JSON-LD": + return new JsonLDStore( new InMemSpdxStore() ); + default: + throw new IllegalArgumentException( "Unknown output format " + outputFormat ); + } + } + + @Override + protected MavenSession newMavenSession( MavenProject project ) + { + MavenExecutionRequest request = new DefaultMavenExecutionRequest(); + MavenExecutionResult result = new DefaultMavenExecutionResult(); + + MavenSession session = new MavenSession( getContainer(), createRepositorySystemSession(), request, result ); + session.setCurrentProject( project ); + session.setProjects( List.of( project ) ); + session.getRequest().setLocalRepository(createLocalArtifactRepository()); + return session; + } + + private RepositorySystemSession createRepositorySystemSession() { + DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); + RepositorySystem repositorySystem = locator.getService( RepositorySystem.class ); + + LocalRepository localRepo = null; + try + { + localRepo = new LocalRepository( Files.createTempDirectory("tmpDirPrefix").toFile() ); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + + DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); + LocalRepositoryManager lrm = repositorySystem.newLocalRepositoryManager( session, localRepo ); + session.setLocalRepositoryManager( lrm ); + + return session; + } + + private ArtifactRepository createLocalArtifactRepository() { + try { + return new MavenArtifactRepository( + "local", + Files.createTempDirectory( "tmpDirPrefix" ).toString(), + new DefaultRepositoryLayout(), + new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE ), + new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE ) + ); + } + catch ( IOException e ) + { + throw new RuntimeException(e); + } + } + + private MavenProject readMavenProject( File pom ) + throws Exception + { + MavenExecutionRequest request = new DefaultMavenExecutionRequest(); + request.setBaseDirectory( new File( getBasedir() ) ); + ProjectBuildingRequest configuration = request.getProjectBuildingRequest(); + configuration.setResolveDependencies( true ); + configuration.setLocalRepository( createLocalArtifactRepository() ); + configuration.setRepositorySession( createRepositorySystemSession() ); + MavenProject project = lookup( ProjectBuilder.class ).build( pom, configuration ).getProject(); + Assert.assertNotNull( project ); + return project; + } + +} diff --git a/src/test/resources/unit/spdx-maven-plugin-test/json-pom-dependencies-v3.xml b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-dependencies-v3.xml new file mode 100644 index 0000000..478b50b --- /dev/null +++ b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-dependencies-v3.xml @@ -0,0 +1,107 @@ + + 4.0.0 + + org.spdx + spdx-maven-plugin-test + 1.0-SNAPSHOT + jar + Test SPDX Plugin + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + http://spdx.org/tools + + Linux Foundation + http://www.linuxfoundation.org + + + UTF-8 + + + + + junit + junit + 4.13.1 + test + + + + + src + Test + + + resources + false + resources + + **/* + + + + META-INF + false + . + + NOTICE + LICENSE + README.txt + changelog + + + + src + + **/*.java + + + + + + Test + + **/*.java + + + + false + TestFiles + + **/* + + + + + + + org.spdx + spdx-maven-plugin + 1.0-SNAPSHOT + + + build-spdx + prepare-package + + createSPDX + + + + + target/test-classes/unit/spdx-maven-plugin-test/test.json-ld.json + JSON-LD + true + http://spdx.org/documents/spdx%20toolsv2.0%20rc1 + Apache-2.0 + true + + + + + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/pom-v3.xml b/src/test/resources/unit/spdx-maven-plugin-test/pom-v3.xml new file mode 100644 index 0000000..90ced3f --- /dev/null +++ b/src/test/resources/unit/spdx-maven-plugin-test/pom-v3.xml @@ -0,0 +1,243 @@ + + 4.0.0 + + org.spdx + spdx maven plugin test + 1.0-SNAPSHOT + jar + Test SPDX Plugin + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + http://spdx.org/tools + + Linux Foundation + http://www.linuxfoundation.org + + + UTF-8 + + + + + junit + junit + 4.13.1 + test + + + org.spdx + java-spdx-library + 1.1.0 + + + + + src + Test + + + resources + false + resources + + **/* + + + + META-INF + false + . + + NOTICE + LICENSE + README.txt + changelog + + + + src + + **/*.java + + + + + + Test + + **/*.java + + + + false + TestFiles + + **/* + + + + + + + org.spdx + spdx-maven-plugin + + + build-spdx + prepare-package + + createSPDX + + + + + + + + target/test-classes/unit/spdx-maven-plugin-test/test.json-ld.json + JSON-LD + http://spdx.org/spdxpackages/spdx toolsv2.0 rc1 + Document Comment + + + Annotation1 + REVIEW + 2010-01-29T18:30:22Z + Person:Test Person + + + Annotation2 + OTHER + 2012-11-29T18:30:22Z + Organization:Test Organization + + + + + PackageAnnotation + REVIEW + 2015-01-29T18:30:22Z + Person:Test Package Person + + + + + LicenseRef-testLicense + Test license text + Test License + + http://www.test.url/testLicense.html + + Test license comment + + + LicenseRef-testLicense2 + Second est license text + Second Test License + + http://www.test.url/testLicense2.html + http://www.test.url/testLicense2-alt.html + + Second Test license comment + + + Copyright (c) 2012, 2013, 2014 Source Auditor Inc. + Default file comment + + First contributor + Second contributor + + Apache-1.1 + Apache-2.0 + Default file license comment + Default file notice + BSD-2-Clause + BSD-3-Clause + Creator comment + + Person: Creator1 + Person: Creator2 + + License comments + Organization: Originating org. + Source info + Copyright Text for Package + + + + SECURITY + + + cpe22Type + + + example-locator-CPE22Type + + + extref comment1 + + + + + PACKAGE-MANAGER + + + maven-central + + + org.apache.tomcat:tomcat:9.0.0.M4 + + + extref comment2 + + + + + + src/main/java/CommonCode.java + Comment for CommonCode + + Contributor to CommonCode + + Common Code Copyright + License Comment for Common Code + Notice for Commmon Code + EPL-1.0 + ISC + + + SnippetName + Snippet Comment + BSD-2-Clause + 44:55 + 1231:3442 + Snippet License Comment + Snippet Copyright Text + BSD-2-Clause-FreeBSD + + + SnippetName2 + Snippet Comment2 + MITNFA + 444:554 + 31231:33442 + Snippet2 License Comment + Snippet2 Copyright Text + LicenseRef-testLicense + + + + + false + + + + + From fd6d6d51028f5733130b30d9dd1877cba2fda6a7 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sun, 15 Dec 2024 11:23:15 -0800 Subject: [PATCH 06/10] Update to released versions of SPDX Java library --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 79e8032..07a741a 100644 --- a/pom.xml +++ b/pom.xml @@ -98,17 +98,17 @@ org.spdx java-spdx-library - 2.0.1-SNAPSHOT + 2.0.0-RC1 org.spdx spdx-rdf-store - 2.0.1-SNAPSHOT + 2.0.0-RC1 org.spdx spdx-jackson-store - 2.0.0-Alpha + 2.0.0-RC1 @@ -150,7 +150,7 @@ org.spdx spdx-v3jsonld-store - 0.1.1-SNAPSHOT + 1.0.0-RC1 From ce8e746b00953010d9e8d71b13c9f4ffaa110f89 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sun, 15 Dec 2024 15:17:47 -0800 Subject: [PATCH 07/10] Add jitpack repository to POM file It seems that jsonschemafriend is no longer available in Maven Central so we need to add the jitpack repository - needed for the Integration Tests --- pom.xml | 7 +++++++ .../org/spdx/maven/utils/ILicenseContainer.java | 16 ---------------- 2 files changed, 7 insertions(+), 16 deletions(-) delete mode 100644 src/main/java/org/spdx/maven/utils/ILicenseContainer.java diff --git a/pom.xml b/pom.xml index 07a741a..f487df0 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,13 @@ master + + + jitpack.io + https://jitpack.io + + + ossrh diff --git a/src/main/java/org/spdx/maven/utils/ILicenseContainer.java b/src/main/java/org/spdx/maven/utils/ILicenseContainer.java deleted file mode 100644 index 0e9d493..0000000 --- a/src/main/java/org/spdx/maven/utils/ILicenseContainer.java +++ /dev/null @@ -1,16 +0,0 @@ -/** - * SPDX-License-Identifier: Apache-2.0 - * Copyright (c) 2024 Source Auditor Inc. - */ -package org.spdx.maven.utils; - -/** - * Interface for a container which contains extracted / non-listed licenses - * - * @author Gary O'Neall - * - */ -public interface ILicenseContainer -{ - -} From 6469e66b64b5e02e58e3d590358a356c59b96b0f Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sun, 15 Dec 2024 15:19:00 -0800 Subject: [PATCH 08/10] Clean up code as suggested by IntelliJ linters --- src/main/java/org/spdx/maven/Annotation.java | 6 +- src/main/java/org/spdx/maven/Checksum.java | 1 + .../java/org/spdx/maven/CreateSpdxMojo.java | 57 +++--- .../org/spdx/maven/ExternalReference.java | 5 +- .../org/spdx/maven/NonStandardLicense.java | 9 +- .../java/org/spdx/maven/OutputFormat.java | 4 +- src/main/java/org/spdx/maven/Packaging.java | 2 +- .../org/spdx/maven/PathSpecificSpdxInfo.java | 7 +- src/main/java/org/spdx/maven/SnippetInfo.java | 16 +- .../utils/AbstractDependencyBuilder.java | 12 +- .../maven/utils/AbstractDocumentBuilder.java | 7 +- .../maven/utils/AbstractFileCollector.java | 45 ++--- .../maven/utils/LicenseManagerException.java | 20 +-- .../maven/utils/LicenseMapperException.java | 8 +- .../maven/utils/MavenToSpdxLicenseMapper.java | 27 +-- .../maven/utils/SpdxBuilderException.java | 6 +- .../maven/utils/SpdxCollectionException.java | 8 +- .../utils/SpdxDefaultFileInformation.java | 14 +- .../maven/utils/SpdxProjectInformation.java | 39 ++--- .../maven/utils/SpdxSourceFileParser.java | 2 +- .../utils/SpdxSourceParserException.java | 31 ++-- .../maven/utils/SpdxV2DependencyBuilder.java | 125 ++++++-------- .../maven/utils/SpdxV2DocumentBuilder.java | 37 ++-- .../spdx/maven/utils/SpdxV2FileCollector.java | 92 +++++----- .../maven/utils/SpdxV2LicenseManager.java | 45 +++-- .../maven/utils/SpdxV3DependencyBuilder.java | 163 ++++++++---------- .../maven/utils/SpdxV3DocumentBuilder.java | 31 ++-- .../spdx/maven/utils/SpdxV3FileCollector.java | 43 ++--- .../maven/utils/SpdxV3LicenseManager.java | 44 +++-- .../maven/utils/TestSpdxV2LicenseManager.java | 10 +- .../maven/utils/TestSpdxV3LicenseManager.java | 10 +- 31 files changed, 417 insertions(+), 509 deletions(-) diff --git a/src/main/java/org/spdx/maven/Annotation.java b/src/main/java/org/spdx/maven/Annotation.java index 2fb1f0d..0f6281e 100644 --- a/src/main/java/org/spdx/maven/Annotation.java +++ b/src/main/java/org/spdx/maven/Annotation.java @@ -23,9 +23,8 @@ * Simple class to hold an SPDX Annotation. * * @author Gary O'Neall - * @see org.spdx.library.model.Annotation - * @see AnnotationType */ +@SuppressWarnings("unused") public class Annotation { private static final Logger LOG = LoggerFactory.getLogger( Annotation.class ); @@ -122,7 +121,6 @@ public void setAnnotationComment( String annotationComment ) public void logInfo() { - LOG.debug( - "Annotator: " + this.annotator + ", Date: " + this.annotationDate + ", Type: " + this.annotationType ); + LOG.debug( "Annotator: {}, Date: {}, Type: {}", this.annotator, this.annotationDate, this.annotationType ); } } \ No newline at end of file diff --git a/src/main/java/org/spdx/maven/Checksum.java b/src/main/java/org/spdx/maven/Checksum.java index d86bba1..17dde3c 100644 --- a/src/main/java/org/spdx/maven/Checksum.java +++ b/src/main/java/org/spdx/maven/Checksum.java @@ -55,6 +55,7 @@ public String getAlgorithm() /** * @param algorithm the algorithm to set */ + @SuppressWarnings("unused") public void setAlgorithm( String algorithm ) { this.algorithm = algorithm; diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index 7974f25..400a1b2 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -57,13 +57,8 @@ import java.io.File; import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; /** * NOTE: Currently this is a prototype plugin for supporting SPDX in a Maven build. @@ -91,6 +86,7 @@ *

* Additional SPDX fields are supplied as configuration parameters to this plugin. */ +@SuppressWarnings({"unused", "DefaultAnnotationParam"}) @Mojo( name = "createSPDX", defaultPhase = LifecyclePhase.VERIFY, requiresOnline = true, @@ -567,7 +563,7 @@ public void execute() throws MojoExecutionException // check errors List spdxErrors = builder.verify(); - if ( spdxErrors != null && spdxErrors.size() > 0 ) + if ( spdxErrors != null && !spdxErrors.isEmpty() ) { getLog().warn( "The following errors were found in the SPDX file:\n " + String.join( "\n ", spdxErrors ) ); } @@ -597,6 +593,7 @@ private OutputFormat prepareOutput() throw new MojoExecutionException( "Invalid path for SPDX output file. " + "Specify a configuration parameter spdxFile with a valid directory path to resolve." ); } + //noinspection ResultOfMethodCallIgnored outputDir.mkdirs(); return outputFormatEnum; } @@ -622,12 +619,12 @@ private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputForm URI namespaceUri = new URI( spdxDocumentNamespace ); if ( SpdxMajorVersion.VERSION_3.equals( outputFormatEnum.getSpecVersion() ) ) { builder = new SpdxV3DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, - this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); + outputFormatEnum ); } else { builder = new SpdxV2DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, - this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); + outputFormatEnum ); } } @@ -662,8 +659,8 @@ private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputForm * Collect dependency information from Maven dependencies and adds it to the builder SPDX document * * @param builder SPDX document builder - * @throws LicenseMapperException - * @throws InvalidSPDXAnalysisException + * @throws LicenseMapperException on errors related to mapping Maven licenses to SPDX licenses + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private void buildSpdxDependencyInformation( AbstractDocumentBuilder builder, OutputFormat outputFormatEnum ) throws LicenseMapperException, InvalidSPDXAnalysisException, DependencyGraphBuilderException @@ -708,19 +705,16 @@ private void logFileSpecificInfo( HashMap fi /** * Get the patch specific information * - * @param projectDefault - * @param spdxDoc SPDX document containing any extracted license infos - * @return - * @throws MojoExecutionException + * @param projectDefault default file information if no path specific overrides are present + * @return map path to project specific SPDX parameters */ - private HashMap getPathSpecificInfoFromParameters( SpdxDefaultFileInformation projectDefault ) throws MojoExecutionException - { + private HashMap getPathSpecificInfoFromParameters( SpdxDefaultFileInformation projectDefault ) { HashMap retval = new HashMap<>(); if ( this.pathsWithSpecificSpdxInfo != null ) { for ( PathSpecificSpdxInfo spdxInfo : this.pathsWithSpecificSpdxInfo ) { - SpdxDefaultFileInformation value = null; + SpdxDefaultFileInformation value; value = spdxInfo.getDefaultFileInformation( projectDefault ); if ( retval.containsKey( spdxInfo.getPath() ) ) { @@ -735,7 +729,7 @@ private HashMap getPathSpecificInfoFromParam /** * Primarily for debugging purposes - logs nonStandardLicenses as info * - * @param nonStandardLicenses + * @param nonStandardLicenses non standard licenses to log */ private void logNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) { @@ -763,7 +757,7 @@ private void logNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) /** * Primarily for debugging purposes - logs includedDirectories as info * - * @param includedDirectories + * @param includedDirectories included directory fileSet to log */ private void logIncludedDirectories( List includedDirectories ) { @@ -792,12 +786,9 @@ private void logIncludedDirectories( List includedDirectories ) } /** - * @param spdxDoc SPDX Document containing any extracted license infos * @return default file information from the plugin parameters - * @throws MojoExecutionException */ - private SpdxDefaultFileInformation getDefaultFileInfoFromParameters() throws MojoExecutionException - { + private SpdxDefaultFileInformation getDefaultFileInfoFromParameters() { SpdxDefaultFileInformation retval; retval = new SpdxDefaultFileInformation(); retval.setComment( defaultFileComment ); @@ -823,17 +814,16 @@ private SpdxDefaultFileInformation getDefaultFileInfoFromParameters() throws Moj * " is prepended * * @param builder SPDX document builder - * @return - * @throws MojoExecutionException + * @return SPDX project level information */ - private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumentBuilder builder ) throws MojoExecutionException, InvalidSPDXAnalysisException + private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumentBuilder builder ) throws InvalidSPDXAnalysisException { SpdxProjectInformation retval = new SpdxProjectInformation(); if ( this.documentComment != null ) { retval.setDocumentComment( this.documentComment ); } - String declaredLicense = null; + String declaredLicense; if ( this.licenseDeclared == null ) { List mavenLicenses = mavenProject.getLicenses(); @@ -851,7 +841,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen { declaredLicense = this.licenseDeclared.trim(); } - String concludedLicense = null; + String concludedLicense; if ( this.licenseConcluded == null ) { concludedLicense = declaredLicense; @@ -866,7 +856,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen { this.creators = new String[0]; } - String[] allCreators = (String[]) Arrays.copyOf( creators, creators.length + 1 ); + String[] allCreators = Arrays.copyOf( creators, creators.length + 1 ); allCreators[allCreators.length - 1] = CREATOR_TOOL_MAVEN_PLUGIN; retval.setCreators( allCreators ); retval.setCopyrightText( this.copyrightText ); @@ -955,7 +945,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumen /** * Get the default project name if no project name is specified in the POM * - * @return + * @return the default project name if no project name is specified in the POM */ private String getDefaultProjectName() { @@ -1010,10 +1000,7 @@ private Set getChecksumAlgorithms() algorithms.add( "SHA1" ); if ( checksumAlgorithms != null ) { - for ( String checksumAlgorithm : checksumAlgorithms ) - { - algorithms.add( checksumAlgorithm ); - } + Collections.addAll( algorithms, checksumAlgorithms ); } return algorithms; } diff --git a/src/main/java/org/spdx/maven/ExternalReference.java b/src/main/java/org/spdx/maven/ExternalReference.java index 0de1ed5..37e778b 100644 --- a/src/main/java/org/spdx/maven/ExternalReference.java +++ b/src/main/java/org/spdx/maven/ExternalReference.java @@ -20,10 +20,9 @@ * enumerations, asset identifiers, or downloadable content believed to be relevant to the Package. * * @author Gary O'Neall - * @see ExternalRef - * @see ReferenceType - * @see ReferenceCategory + * */ +@SuppressWarnings("unused") public class ExternalReference { private String category; diff --git a/src/main/java/org/spdx/maven/NonStandardLicense.java b/src/main/java/org/spdx/maven/NonStandardLicense.java index 78dd59d..7749cd9 100644 --- a/src/main/java/org/spdx/maven/NonStandardLicense.java +++ b/src/main/java/org/spdx/maven/NonStandardLicense.java @@ -16,9 +16,10 @@ package org.spdx.maven; import java.net.URL; +import java.util.Objects; /** - * Non-standard license (e.g. license which is not in the SPDX standard license list http://spdx.org/licenses) + * Non-standard license (e.g. license which is not in the SPDX standard license list) * * @author Gary O'Neall */ @@ -94,11 +95,7 @@ public String getName() */ public String getComment() { - if ( comment == null ) - { - return ""; - } - return comment; + return Objects.requireNonNullElse( comment, "" ); } /** diff --git a/src/main/java/org/spdx/maven/OutputFormat.java b/src/main/java/org/spdx/maven/OutputFormat.java index 4efc299..d4c2c57 100644 --- a/src/main/java/org/spdx/maven/OutputFormat.java +++ b/src/main/java/org/spdx/maven/OutputFormat.java @@ -35,8 +35,8 @@ public enum OutputFormat private final String fileType; private final SpdxMajorVersion specVersion; - private OutputFormat(final String value, final String artifactType, final String fileType, - final SpdxMajorVersion specVersion) + OutputFormat( final String value, final String artifactType, final String fileType, + final SpdxMajorVersion specVersion ) { this.value = value; this.artifactType = artifactType; diff --git a/src/main/java/org/spdx/maven/Packaging.java b/src/main/java/org/spdx/maven/Packaging.java index cadefe2..153b7c3 100644 --- a/src/main/java/org/spdx/maven/Packaging.java +++ b/src/main/java/org/spdx/maven/Packaging.java @@ -37,7 +37,7 @@ public enum Packaging private final Purpose v2Purpose; private final SoftwarePurpose softwarePurpose; - private Packaging(final String name, final Purpose v2purpose, final SoftwarePurpose v3softwarePurpose) + Packaging( final String name, final Purpose v2purpose, final SoftwarePurpose v3softwarePurpose ) { this.name = name; this.v2Purpose = v2purpose; diff --git a/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java b/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java index 06fe049..1035d61 100644 --- a/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java +++ b/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java @@ -24,6 +24,7 @@ * * @author Gary O'Neall */ +@SuppressWarnings("unused") public class PathSpecificSpdxInfo { /** @@ -82,7 +83,7 @@ public class PathSpecificSpdxInfo * or (d) NOASSERTION, if the SPDX file creator has not examined the contents of the actual file or the SPDX file * creator has intentionally provided no information (no meaning should be implied by doing so). For a license set, * when there is a choice between licenses (“disjunctive license”), they should be separated with “or” and enclosed - * in brackets. Similarly when multiple licenses need to be applied (“conjunctive license”), they should be + * in brackets. Similarly, when multiple licenses need to be applied (“conjunctive license”), they should be * separated with “and” and enclosed in parentheses. */ private String licenseInformationInFile; @@ -101,10 +102,8 @@ public PathSpecificSpdxInfo() * Get the default file information to be used with this file path * * @param defaults Default file information to use if the parameter was not specified for this file path - * @param spdxDoc SPDX document containing any extracted license infos that may be needed for concluded or declared - * licenses + * @return default file information to be used with this file path - * @throws InvalidSPDXAnalysisException */ public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInformation defaults ) { diff --git a/src/main/java/org/spdx/maven/SnippetInfo.java b/src/main/java/org/spdx/maven/SnippetInfo.java index a0620a1..60c3a31 100644 --- a/src/main/java/org/spdx/maven/SnippetInfo.java +++ b/src/main/java/org/spdx/maven/SnippetInfo.java @@ -57,26 +57,26 @@ public void logInfo() LOG.debug( "Snippet information follows:" ); if ( this.name != null ) { - LOG.debug( "Name: " + this.name ); + LOG.debug( "Name: {}", this.name ); } - LOG.debug( "Byte range: " + this.byteRange ); + LOG.debug( "Byte range: {}", this.byteRange ); if ( this.comment != null ) { - LOG.debug( "Comment: " + this.comment ); + LOG.debug( "Comment: {}", this.comment ); } - LOG.debug( "Concluded license: " + this.concludedLicense ); + LOG.debug( "Concluded license: {}", this.concludedLicense ); if ( this.copyrightText != null ) { - LOG.debug( "Copyright: " + this.copyrightText ); + LOG.debug( "Copyright: {}", this.copyrightText ); } if ( this.licenseComment != null ) { - LOG.debug( "License comment: " + this.licenseComment ); + LOG.debug( "License comment: {}", this.licenseComment ); } - LOG.debug( "License info in Snippet: " + this.licenseInfoInSnippet ); + LOG.debug( "License info in Snippet: {}", this.licenseInfoInSnippet ); if ( this.lineRange != null ) { - LOG.debug( "Line range: " + this.lineRange ); + LOG.debug( "Line range: {}", this.lineRange ); } } diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java index fee8344..04b0a9b 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java @@ -27,7 +27,7 @@ /** * Contains information about package dependencies collected from the Maven dependencies. - * + *

* Subclasses implement dependency information specific to SPDX spec major versions * * @author Gary O'Neall @@ -107,7 +107,7 @@ abstract void addMavenDependency( CoreModelObject parentPackage, DependencyNode if ( versionFilter == null || versionFilter.equals( of.getSpecVersion() )) { File retval = getFileWithDifferentType( file, of.getFileType() ); - if ( retval != null && retval.exists() ) { + if ( retval.exists() ) { return retval; } } @@ -131,8 +131,7 @@ private File getFileWithDifferentType( File file, String type ) filePath = filePath.substring( 0, indexOfDot + 1 ); } filePath = filePath + type; - File retval = new File( filePath ); - return retval; + return new File( filePath ); } private void logDependencies( List dependencies ) @@ -157,15 +156,14 @@ private void logDependencies( List dependencies ) Artifact dependency = node.getArtifact(); String filePath = dependency.getFile() != null ? dependency.getFile().getAbsolutePath() : "[NONE]"; String scope = dependency.getScope() != null ? dependency.getScope() : "[NONE]"; - LOG.debug( - "ArtifactId: " + dependency.getArtifactId() + ", file path: " + filePath + ", Scope: " + scope ); + LOG.debug("ArtifactId: {}, file path: {}, Scope: {}", dependency.getArtifactId(), filePath, scope); } } /** * Make an external document reference ID valid by replacing any invalid characters with dashes * - * @param externalRefId + * @param externalRefId ID for external reference * @return valid external ref ID */ protected String fixExternalRefId( String externalRefId ) diff --git a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java index bb066d3..107bb21 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java @@ -24,7 +24,7 @@ /** * Abstract class to create SPDX documents. - * + *

* Subclasses of this class implement specific SPDX specification versions of the document * * @author Gary O'Neall @@ -38,7 +38,6 @@ public abstract class AbstractDocumentBuilder protected boolean generatePurls; protected File spdxFile; protected OutputFormat outputFormatEnum; - protected boolean matchLicensesOnCrossReferenceUrls; protected ISerializableModelStore modelStore; protected ModelCopyManager copyManager; protected DateFormat format = new SimpleDateFormat( SpdxConstantsCompatV2.SPDX_DATE_FORMAT ); @@ -104,7 +103,7 @@ public AbstractDocumentBuilder( MavenProject project, boolean generatePurls, Fil * @param baseDir project base directory used to construct the relative paths for the SPDX * files * @param pathSpecificInformation Map of path to file information used to override the default file information - * @param algorithms algorithms to use to generate checksums + * @param checksumAlgorithms algorithms to use to generate checksums * @throws SpdxBuilderException on errors collecting files */ public abstract void collectSpdxFileInformation( List sources, String baseDir, @@ -120,7 +119,7 @@ public abstract void collectSpdxFileInformation( List sources, String b public abstract void saveSpdxDocumentToFile() throws SpdxBuilderException; /** - * @param nonStandardLicenses + * @param nonStandardLicenses non standard licenses to add */ public abstract void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException; diff --git a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java index 5393255..944d832 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java +++ b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java @@ -13,7 +13,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -28,7 +27,7 @@ /** * Collects SPDX file information from directories. - * + *

* Concrete subclasses implement specific SPDX spec specific formats * * @author Gary O'Neall @@ -77,26 +76,19 @@ private static void loadFileExtensionConstants() return; } prop.load( is ); - Iterator> iter = prop.entrySet().iterator(); - while ( iter.hasNext() ) - { - Entry entry = iter.next(); - String fileTypeStr = (String)entry.getKey(); - FileType fileType = FileType.valueOf( fileTypeStr ); - String[] extensions = ((String)entry.getValue()).split( "," ); - for ( String extension:extensions ) - { - try - { + for (Entry entry : prop.entrySet()) { + String fileTypeStr = (String) entry.getKey(); + FileType fileType = FileType.valueOf(fileTypeStr); + String[] extensions = ((String) entry.getValue()).split(","); + for (String extension : extensions) { + try { String trimmedExtension = extension.toUpperCase().trim(); - if ( EXT_TO_FILE_TYPE.containsKey( trimmedExtension ) ) - { - LOG.warn( "Duplicate file extension: "+trimmedExtension ); + if (EXT_TO_FILE_TYPE.containsKey(trimmedExtension)) { + LOG.warn("Duplicate file extension: {}", trimmedExtension); } - EXT_TO_FILE_TYPE.put( trimmedExtension, fileType ); - } - catch ( Exception ex ) { - LOG.error( "Error adding file extensions to filetype map", ex ); + EXT_TO_FILE_TYPE.put(trimmedExtension, fileType); + } catch (Exception ex) { + LOG.error("Error adding file extensions to filetype map", ex); } } } @@ -123,7 +115,7 @@ public String getExtension( File file ) } /** - * @param fileTypes + * @param fileTypes list of file types for the file * @return true if the fileTypes contain a source file type */ protected boolean isSourceFile( Collection fileTypes ) @@ -143,7 +135,7 @@ protected boolean isSourceFile( Collection fileTypes ) * * @param filePath system specific file path relative to the top of the archive root to the top of the archive * directory where the file is stored. - * @return + * @return valid SPDX file name per the spec */ public String convertFilePathToSpdxFileName( String filePath ) { @@ -164,8 +156,8 @@ protected static FileType extensionToFileType( String fileExtension ) /** * Converts an array of bytes to a string compliant with the SPDX sha1 representation * - * @param digestBytes - * @return + * @param digestBytes result of a checksum digest calculation + * @return string representation of the checksum per the SPDX specification */ public static String convertChecksumToString( byte[] digestBytes ) { @@ -187,10 +179,9 @@ public static String convertChecksumToString( byte[] digestBytes ) * {@code SpdxFileCollector.generateChecksum(file, "SHA-1")}. * * @param file file to generate checksum for - * @param builder Builder for the SPDX document that will contain the checksum * @return SHA1 checksum of the input file * @throws SpdxCollectionException if the algorithm is unavailable or the file cannot be read - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ public static Checksum generateSha1( File file ) throws SpdxCollectionException, InvalidSPDXAnalysisException { @@ -206,7 +197,7 @@ public static Checksum generateSha1( File file ) throws SpdxCollectionException, * @param algorithms algorithms to generate the checksums * @return {@code Set} of checksums for file using each algorithm specified * @throws SpdxCollectionException if the input algorithm is invalid or unavailable or if the file cannot be read - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ public static Set generateChecksum( File file, Set algorithms ) throws SpdxCollectionException, InvalidSPDXAnalysisException { diff --git a/src/main/java/org/spdx/maven/utils/LicenseManagerException.java b/src/main/java/org/spdx/maven/utils/LicenseManagerException.java index 0e576ac..61957dc 100644 --- a/src/main/java/org/spdx/maven/utils/LicenseManagerException.java +++ b/src/main/java/org/spdx/maven/utils/LicenseManagerException.java @@ -29,28 +29,28 @@ public class LicenseManagerException extends Exception private static final long serialVersionUID = 1672757028355331818L; /** - * @param arg0 + * @param msg message */ - public LicenseManagerException( String arg0 ) + public LicenseManagerException( String msg ) { - super( arg0 ); + super( msg ); } /** - * @param arg0 + * @param inner inner exception */ - public LicenseManagerException( Throwable arg0 ) + public LicenseManagerException( Throwable inner ) { - super( arg0 ); + super( inner ); } /** - * @param arg0 - * @param arg1 + * @param msg message + * @param inner inner exception */ - public LicenseManagerException( String arg0, Throwable arg1 ) + public LicenseManagerException( String msg, Throwable inner ) { - super( arg0, arg1 ); + super( msg, inner ); } } diff --git a/src/main/java/org/spdx/maven/utils/LicenseMapperException.java b/src/main/java/org/spdx/maven/utils/LicenseMapperException.java index b6ee99c..2f4ba0e 100644 --- a/src/main/java/org/spdx/maven/utils/LicenseMapperException.java +++ b/src/main/java/org/spdx/maven/utils/LicenseMapperException.java @@ -37,7 +37,7 @@ public LicenseMapperException() } /** - * @param message + * @param message message */ public LicenseMapperException( String message ) { @@ -45,7 +45,7 @@ public LicenseMapperException( String message ) } /** - * @param cause + * @param cause inner exception */ public LicenseMapperException( Throwable cause ) { @@ -53,8 +53,8 @@ public LicenseMapperException( Throwable cause ) } /** - * @param message - * @param cause + * @param message message + * @param cause inner exception */ public LicenseMapperException( String message, Throwable cause ) { diff --git a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java index 507c61a..dee3991 100644 --- a/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java +++ b/src/main/java/org/spdx/maven/utils/MavenToSpdxLicenseMapper.java @@ -66,7 +66,7 @@ public class MavenToSpdxLicenseMapper private static final String LISTED_LICENSE_JSON_PATH = "resources/licenses.json"; static volatile MavenToSpdxLicenseMapper instance; - private static Object instanceMutex = new Object(); + private static final Object instanceMutex = new Object(); private Map urlStringToSpdxLicenseId; private MavenToSpdxLicenseMapper() throws LicenseMapperException @@ -94,6 +94,12 @@ private MavenToSpdxLicenseMapper() throws LicenseMapperException is = SpdxV2LicenseManager.class.getClassLoader().getResourceAsStream( LISTED_LICENSE_JSON_PATH ); } + if ( is == null ) + { + LOG.error( "Could not load the resource {}", LISTED_LICENSE_JSON_PATH); + throw new LicenseMapperException( "Unable to load the listed licenses file" ); + } + try (BufferedReader reader = new BufferedReader( new InputStreamReader( is, Charset.defaultCharset() ) )) { initializeUrlMap( reader ); @@ -134,7 +140,7 @@ public String urlToSpdxId( String url ) * Initialize the urlStringToSpdxLicense map with the SPDX listed licenses * * @param jsonReader Reader for the JSON input file containing the listed licenses - * @throws LicenseMapperException + * @throws LicenseMapperException on errors accessing the listed license or parsing errors */ private void initializeUrlMap( BufferedReader jsonReader ) throws LicenseMapperException { @@ -209,8 +215,8 @@ private void addManualMappings() * * @param licenseList list of licenses * @param spdxDoc SPDX document which will hold the licenses - * @return - * @throws InvalidSPDXAnalysisException + * @return SPDX license which matches the list of maven licenses + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ public AnyLicenseInfo mavenLicenseListToSpdxV2License( List licenseList, SpdxDocument spdxDoc ) throws InvalidSPDXAnalysisException { @@ -227,7 +233,7 @@ public AnyLicenseInfo mavenLicenseListToSpdxV2License( List licenseList spdxLicenses.add( listedLicense ); } } - if ( spdxLicenses.size() < 1 ) + if (spdxLicenses.isEmpty()) { return new SpdxNoAssertionLicense(); } @@ -237,8 +243,7 @@ else if ( spdxLicenses.size() == 1 ) } else { - AnyLicenseInfo conjunctiveLicense = spdxDoc.createConjunctiveLicenseSet( spdxLicenses ); - return conjunctiveLicense; + return spdxDoc.createConjunctiveLicenseSet( spdxLicenses ); } } @@ -274,10 +279,10 @@ private SpdxListedLicense mavenLicenseToSpdxV2ListedLicense( License license ) * SpdxNoAssertion is returned. If multiple licenses are supplied, a conjunctive license is returned containing all * mapped SPDX licenses. * - * @param licenseList list of licenses + * @param licenseList list of Maven licenses * @param spdxDoc SPDX document which will hold the licenses - * @return - * @throws InvalidSPDXAnalysisException + * @return SPDX version 3 license equivalent to the list of Maven licenses + * @throws InvalidSPDXAnalysisException On SPDX parsing errors */ public org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo mavenLicenseListToSpdxV3License( List licenseList, Element spdxDoc ) throws InvalidSPDXAnalysisException @@ -295,7 +300,7 @@ public org.spdx.library.model.v3_0_1.simplelicensing.AnyLicenseInfo mavenLicense spdxLicenses.add( listedLicense ); } } - if ( spdxLicenses.size() < 1 ) + if (spdxLicenses.isEmpty()) { return new NoAssertionLicense(); } diff --git a/src/main/java/org/spdx/maven/utils/SpdxBuilderException.java b/src/main/java/org/spdx/maven/utils/SpdxBuilderException.java index f5ccf93..bf53eab 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxBuilderException.java +++ b/src/main/java/org/spdx/maven/utils/SpdxBuilderException.java @@ -31,7 +31,7 @@ public class SpdxBuilderException extends MojoExecutionException private static final long serialVersionUID = 1L; /** - * @param message + * @param message message */ public SpdxBuilderException( String message ) { @@ -39,8 +39,8 @@ public SpdxBuilderException( String message ) } /** - * @param message - * @param cause + * @param message message + * @param cause inner exception */ public SpdxBuilderException( String message, Throwable cause ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxCollectionException.java b/src/main/java/org/spdx/maven/utils/SpdxCollectionException.java index 1d5d8ca..cc78566 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxCollectionException.java +++ b/src/main/java/org/spdx/maven/utils/SpdxCollectionException.java @@ -37,7 +37,7 @@ public SpdxCollectionException() } /** - * @param message + * @param message message */ public SpdxCollectionException( String message ) { @@ -45,7 +45,7 @@ public SpdxCollectionException( String message ) } /** - * @param cause + * @param cause inner exception */ public SpdxCollectionException( Throwable cause ) { @@ -53,8 +53,8 @@ public SpdxCollectionException( Throwable cause ) } /** - * @param message - * @param cause + * @param message message + * @param cause inner exception */ public SpdxCollectionException( String message, Throwable cause ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java index 625380c..5fc5120 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java @@ -139,17 +139,17 @@ public void setSnippets( List snippets ) */ public void logInfo() { - LOG.debug( "Default File Comment: " + getComment() ); - LOG.debug( "Default File Copyright: " + getCopyright() ); - LOG.debug( "Default File License Comment: " + getLicenseComment() ); - LOG.debug( "Default File Notice: " + getNotice() ); - LOG.debug( "Default File Concluded License: " + getConcludedLicense().toString() ); - LOG.debug( "Default File Declared License: " + getDeclaredLicense().toString() ); + LOG.debug("Default File Comment: {}", getComment()); + LOG.debug("Default File Copyright: {}", getCopyright()); + LOG.debug("Default File License Comment: {}", getLicenseComment()); + LOG.debug("Default File Notice: {}", getNotice()); + LOG.debug("Default File Concluded License: {}", getConcludedLicense()); + LOG.debug("Default File Declared License: {}", getDeclaredLicense()); if ( contributors != null ) { for ( String contributor : contributors ) { - LOG.debug( "Default File Contributors: " + contributor ); + LOG.debug("Default File Contributors: {}", contributor); } } if ( this.snippets != null ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java index 6840f60..bbad242 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java @@ -338,21 +338,21 @@ public void logInfo() if ( !LOG.isDebugEnabled() ) { return; } - LOG.debug( "SPDX Project Name: " + this.getName() ); - LOG.debug( "SPDX Document comment: " + this.getDocumentComment() ); - LOG.debug( "SPDX Creator comment: " + this.getCreatorComment() ); - LOG.debug( "SPDX Description: " + this.getDescription() ); - LOG.debug( "SPDX License comment: " + this.getLicenseComment() ); - LOG.debug( "SPDX Originator: " + this.getOriginator() ); - LOG.debug( "SPDX PackageArchiveFileName: " + this.getPackageArchiveFileName() ); - LOG.debug( "SPDX Short description: " + this.getShortDescription() ); - LOG.debug( "SPDX Supplier: " + this.getSupplier() ); - LOG.debug( "SPDX Source Info: " + this.getSourceInfo() ); - LOG.debug( "SPDX Version info: " + this.getVersionInfo() ); - LOG.debug( "SPDX Concluded license: " + this.getConcludedLicense().toString() ); - LOG.debug( "SPDX Declared license: " + this.getDeclaredLicense().toString() ); - LOG.debug( "SPDX Download URL: " + this.getDownloadUrl() ); - LOG.debug( "SPDX Home page: " + this.getHomePage() ); + LOG.debug("SPDX Project Name: {}", this.getName()); + LOG.debug("SPDX Document comment: {}", this.getDocumentComment()); + LOG.debug("SPDX Creator comment: {}", this.getCreatorComment()); + LOG.debug("SPDX Description: {}", this.getDescription()); + LOG.debug("SPDX License comment: {}", this.getLicenseComment()); + LOG.debug("SPDX Originator: {}", this.getOriginator()); + LOG.debug("SPDX PackageArchiveFileName: {}", this.getPackageArchiveFileName()); + LOG.debug("SPDX Short description: {}", this.getShortDescription()); + LOG.debug("SPDX Supplier: {}", this.getSupplier()); + LOG.debug("SPDX Source Info: {}", this.getSourceInfo()); + LOG.debug("SPDX Version info: {}", this.getVersionInfo()); + LOG.debug("SPDX Concluded license: {}", this.getConcludedLicense()); + LOG.debug("SPDX Declared license: {}", this.getDeclaredLicense()); + LOG.debug("SPDX Download URL: {}", this.getDownloadUrl()); + LOG.debug("SPDX Home page: {}", this.getHomePage()); if ( this.documentAnnotations != null && this.documentAnnotations.length > 0 ) { LOG.debug( "Document annotations: " ); @@ -373,22 +373,21 @@ public void logInfo() { for ( String creator : creators ) { - LOG.debug( "SPDX Creator: " + creator ); + LOG.debug("SPDX Creator: {}", creator); } } if ( this.externalRefs != null ) { for ( ExternalReference externalReference : externalRefs ) { - LOG.debug( String.format( "External Ref: %s %s %s", externalReference.getCategory(), - externalReference.getType(), externalReference.getLocator()) ); + LOG.debug("External Ref: {} {} {}", externalReference.getCategory(), externalReference.getType(), externalReference.getLocator()); } } - if ( checksums != null && checksums.size() > 0 ) + if ( checksums != null && !checksums.isEmpty()) { for ( Checksum checksum : checksums ) { - LOG.debug( "SPDX " + checksum.getAlgorithm() + ": " + checksum.getValue() ); + LOG.debug("SPDX {}: {}", checksum.getAlgorithm(), checksum.getValue()); } } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java b/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java index 8462c46..1c376af 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java +++ b/src/main/java/org/spdx/maven/utils/SpdxSourceFileParser.java @@ -67,7 +67,7 @@ public static List parseTextForSpdxLicenses( String text ) throws SpdxSo String matchingLine = match.group( 1 ).trim(); if ( matchingLine.startsWith( "(" ) ) { - // This could be a multi-line expression, so we need to parse until we get to the last ) + // This could be a multi-line expression, so we need to parse until we get to the last ")" int parenCount = 1; StringBuilder sb = new StringBuilder( "(" ); pos = match.start( 1 ) + 1; diff --git a/src/main/java/org/spdx/maven/utils/SpdxSourceParserException.java b/src/main/java/org/spdx/maven/utils/SpdxSourceParserException.java index 4a3e599..19bb83f 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxSourceParserException.java +++ b/src/main/java/org/spdx/maven/utils/SpdxSourceParserException.java @@ -18,39 +18,28 @@ public class SpdxSourceParserException extends Exception private static final long serialVersionUID = 1L; /** - * @param arg0 + * @param msg message */ - public SpdxSourceParserException( String arg0 ) + public SpdxSourceParserException( String msg ) { - super( arg0 ); + super( msg ); } /** - * @param arg0 + * @param cause inner exception */ - public SpdxSourceParserException( Throwable arg0 ) + public SpdxSourceParserException( Throwable cause ) { - super( arg0 ); + super( cause ); } /** - * @param arg0 - * @param arg1 + * @param msg message + * @param cause inner exception */ - public SpdxSourceParserException( String arg0, Throwable arg1 ) + public SpdxSourceParserException( String msg, Throwable cause ) { - super( arg0, arg1 ); - } - - /** - * @param arg0 - * @param arg1 - * @param arg2 - * @param arg3 - */ - public SpdxSourceParserException( String arg0, Throwable arg1, boolean arg2, boolean arg3 ) - { - super( arg0, arg1, arg2, arg3 ); + super( msg, cause ); } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java index 6129301..f8101b9 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java @@ -97,15 +97,10 @@ protected static SpdxDocument spdxDocumentFromFile( String path ) throws FileNot } finally { - if ( modelStore != null ) { - try - { - modelStore.close(); - } - catch ( Exception e ) - { - LOG.error( "Error closing SPDX model store", e ); - } + try { + modelStore.close(); + } catch (Exception e) { + LOG.error("Error closing SPDX model store", e); } } } @@ -124,7 +119,7 @@ protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument external for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) { Optional name = item.getName(); - if ( item instanceof SpdxPackage && name.isPresent() && item.getName().get().equals( artifactId ) ) + if ( item instanceof SpdxPackage && name.isPresent() && item.getName().orElse( "" ).equals( artifactId ) ) { itemDescribed = item; break; @@ -132,7 +127,7 @@ protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument external } if ( itemDescribed == null ) { // Find the first package - LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in SPDX file." ); + LOG.warn("Could not find matching artifact ID in SPDX file for {}. Using the first package found in SPDX file.", artifactId); for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) { if ( item instanceof SpdxPackage ) @@ -151,10 +146,9 @@ protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument external /** * Map of namespaces to ExternalDocumentRefs */ - private Map externalDocuments = new HashMap<>(); - private List documentAnnotations = new ArrayList<>(); - private SpdxDocument spdxDoc; - private SpdxV2LicenseManager licenseManager; + private final Map externalDocuments = new HashMap<>(); + private final SpdxDocument spdxDoc; + private final SpdxV2LicenseManager licenseManager; /** * @param builder The document builder @@ -180,8 +174,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { if ( !(parentPackage instanceof SpdxPackage) ) { - LOG.error( String.format( "Invalid type for parent package. Expected 'SpdxPackage', found %s", - parentPackage.getClass().getName() ) ); + LOG.error("Invalid type for parent package. Expected 'SpdxPackage', found {}", parentPackage.getClass().getName()); return; } Artifact dependency = dependencyNode.getArtifact(); @@ -189,8 +182,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); if ( relType == RelationshipType.OTHER ) { - LOG.warn( - "Could not determine the SPDX relationship type for dependency artifact ID " + dependency.getArtifactId() + " scope " + scope ); + LOG.warn("Could not determine the SPDX relationship type for dependency artifact ID {} scope {}", dependency.getArtifactId(), scope); } SpdxElement dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, @@ -202,13 +194,13 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { ((SpdxPackage)parentPackage).addRelationship( spdxDoc.createRelationship( dependencyPackage, relType, "Relationship created based on Maven POM information" ) ); - LOG.debug( "Added relationship of type " + relType + " for " + dependencyPackage.getName() ); + LOG.debug("Added relationship of type {} for {}", relType, dependencyPackage.getName()); } else { ((SpdxPackage)parentPackage).addRelationship(spdxDoc.createRelationship( (SpdxPackage)parentPackage, RelationshipType.OTHER, "This relationship is the inverse of " + relType + " to an external document reference." ) ); - LOG.debug( "Could not create proper to relationships for external element " + dependencyPackage.getId() ); + LOG.debug("Could not create proper to relationships for external element {}", dependencyPackage.getId()); } } else @@ -225,9 +217,9 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode /** * Translate the scope to the SPDX relationship type * - * @param scope Maven Dependency Scope (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope) + * @param scope Maven Dependency Scope (see Maven dependency scope documentation) * @param optional True if this is an optional dependency - * @return SPDX Relationship type based on the scope + * @return SPDX Relationship type based on the scope */ private RelationshipType scopeToRelationshipType( String scope, boolean optional ) { @@ -259,7 +251,6 @@ else if ( scope.equals( "test" ) ) * @param project Maven project * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used * @return SPDX Package generated from the metadata in the Maven Project - * @throws IOException On errors reading Maven file information * @throws SpdxCollectionException On errors with SPDX collections * @throws NoSuchAlgorithmException if no checksum algorithm was found * @throws LicenseMapperException on errors mapping or creating SPDX custom licenses @@ -320,7 +311,7 @@ packageName, new SpdxNoAssertionLicense(), copyright, declaredLicense ) try { retval.setHomepage( project.getUrl() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( "Invalid homepage for dependency " + project.getArtifactId() + ": " + project.getUrl() ); + LOG.warn("Invalid homepage for dependency {}: {}", project.getArtifactId(), project.getUrl()); } } return retval; @@ -342,14 +333,14 @@ private SpdxElement createSpdxPackage( Artifact artifact, ProjectBuilder mavenProjectBuilder, MavenSession session, MavenProject mavenProject, boolean useArtifactID ) throws LicenseMapperException, InvalidSPDXAnalysisException { - LOG.debug( "Creating SPDX package for artifact " + artifact.getArtifactId() ); + LOG.debug("Creating SPDX package for artifact {}", artifact.getArtifactId()); if ( artifact.getFile() == null ) { LOG.debug( "Artifact file is null" ); } else { - LOG.debug( "Artifact file name = " + artifact.getFile().getName() ); + LOG.debug("Artifact file name = {}", artifact.getFile().getName()); } File spdxFile = null; if ( artifact.getFile() != null ) @@ -358,12 +349,10 @@ private SpdxElement createSpdxPackage( Artifact artifact, } if ( spdxFile != null && spdxFile.exists() ) { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Looking for SPDX file " + spdxFile.getAbsolutePath() ); + LOG.debug("Dependency {}Looking for SPDX file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath()); try { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Dependency information collected from SPDX file " + spdxFile.getAbsolutePath() ); + LOG.debug("Dependency {}Dependency information collected from SPDX file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath()); SpdxDocument externalSpdxDoc = spdxDocumentFromFile( spdxFile.getPath() ); if ( createExternalRefs ) @@ -373,34 +362,28 @@ private SpdxElement createSpdxPackage( Artifact artifact, } else { - return copyPackageInfoFromExternalDoc( externalSpdxDoc, artifact.getGroupId(), - artifact.getArtifactId(), artifact.getVersion() ); + return copyPackageInfoFromExternalDoc( externalSpdxDoc, artifact.getArtifactId() ); } } catch ( IOException e ) { - LOG.warn( - "IO error reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn("IO error reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); } catch ( SpdxInvalidIdException e ) { - LOG.warn( - "Invalid SPDX ID exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn("Invalid SPDX ID exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( - "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn("Invalid SPDX analysis exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); } catch ( SpdxCollectionException e ) { - LOG.warn( - "Unable to create file checksum for external SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn("Unable to create file checksum for external SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); } catch ( Exception e ) { - LOG.warn( - "Unknown error processing SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn("Unknown error processing SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); } } try @@ -408,40 +391,34 @@ private SpdxElement createSpdxPackage( Artifact artifact, ProjectBuildingRequest request = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); request.setRemoteRepositories( mavenProject.getRemoteArtifactRepositories() ); for ( ArtifactRepository ar : request.getRemoteRepositories() ) { - LOG.debug( "request Remote repository ID: " + ar.getId() ); + LOG.debug("request Remote repository ID: {}", ar.getId()); } for ( ArtifactRepository ar : mavenProject.getRemoteArtifactRepositories() ) { - LOG.debug( "Project Remote repository ID: " + ar.getId() ); + LOG.debug("Project Remote repository ID: {}", ar.getId()); } ProjectBuildingResult build = mavenProjectBuilder.build( artifact, request ); MavenProject depProject = build.getProject(); - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Collecting information from project metadata for " + depProject.getArtifactId() ); + LOG.debug("Dependency {}Collecting information from project metadata for {}", artifact.getArtifactId(), depProject.getArtifactId()); return createSpdxPackage( depProject, useArtifactID ); } catch ( SpdxCollectionException e ) { - LOG.error( - "SPDX File Collection Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error("SPDX File Collection Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); } catch ( NoSuchAlgorithmException e ) { - LOG.error( - "Verification Code Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error("Verification Code Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); } catch ( ProjectBuildingException e ) { - LOG.error( - "Maven Project Build Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error("Maven Project Build Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); } - LOG.warn( - "Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ". A minimal SPDX package will be created." ); + LOG.warn("Error creating SPDX package for dependency artifact ID {}. A minimal SPDX package will be created.", artifact.getArtifactId()); // Create a minimal SPDX package from dependency // Name will be the artifact ID - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Using only artifact information to create dependent package" ); - SpdxPackage pkg = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), - artifact.getArtifactId(), new SpdxNoAssertionLicense(), "NOASSERTION", + LOG.debug("Dependency {}Using only artifact information to create dependent package", artifact.getArtifactId()); + return spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), + artifact.getArtifactId(), new SpdxNoAssertionLicense(), "NOASSERTION", new SpdxNoAssertionLicense() ) .setComment( "This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file." ) .setVersionInfo( artifact.getBaseVersion() ) @@ -449,7 +426,6 @@ private SpdxElement createSpdxPackage( Artifact artifact, .setDownloadLocation( "NOASSERTION" ) .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, mavenProject ) ) .build(); - return pkg; } /** @@ -461,8 +437,8 @@ private SpdxElement createSpdxPackage( Artifact artifact, * @param artifactId Artifact ID for the external artifact * @param version version for the external artifact * @return created SPDX element - * @throws SpdxCollectionException - * @throws InvalidSPDXAnalysisException + * @throws SpdxCollectionException on incompatible types for collections + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpdxDoc, File spdxFile, @@ -480,7 +456,7 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd if ( externalRef == null ) { String externalRefDocId = SpdxConstantsCompatV2.EXTERNAL_DOC_REF_PRENUM + fixExternalRefId( fullArtifactId ); - LOG.debug( "Creating external document ref " + externalDocNamespace ); + LOG.debug("Creating external document ref {}", externalDocNamespace); org.spdx.maven.Checksum mavenChecksum = AbstractFileCollector.generateSha1( spdxFile ); Checksum cksum = spdxDoc.createChecksum( ChecksumAlgorithm.valueOf( mavenChecksum.getAlgorithm() ), mavenChecksum.getValue() ); @@ -491,9 +467,8 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd format.format( new Date() ), "External document ref '"+externalRefDocId+"' created for artifact "+fullArtifactId ); spdxDoc.getAnnotations().add( docRefAddedAnnotation ); - this.documentAnnotations.add( docRefAddedAnnotation ); this.externalDocuments.put( externalDocNamespace, externalRef ); - LOG.debug( "Created external document ref " + externalRefDocId ); + LOG.debug("Created external document ref {}", externalRefDocId); } SpdxPackage pkg = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); return new ExternalSpdxElement( spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), @@ -502,26 +477,23 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd /** * Copies the closest matching described package in the externalSpdxDoc to the returned element - * @param externalSpdxDoc - * @param groupId Group ID of the artifact + * @param externalSpdxDoc SPDX document to copy from * @param artifactId Artifact ID to search for - * @param version Version of the artifact * @return SPDX Package with values copied from the externalSpdxDoc - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ - private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc, String groupId, - String artifactId, String version ) throws InvalidSPDXAnalysisException + private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc, String artifactId ) throws InvalidSPDXAnalysisException { SpdxPackage source = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); Optional downloadLocation = source.getDownloadLocation(); Optional name = source.getName(); SpdxPackage dest = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), - name.isPresent() ? name.get() : "NONE", source.getLicenseConcluded(), source.getCopyrightText(), + name.orElse("NONE"), source.getLicenseConcluded(), source.getCopyrightText(), source.getLicenseDeclared() ) .setFilesAnalyzed( false ) .setAnnotations( source.getAnnotations() ) .setChecksums( source.getChecksums() ) - .setDownloadLocation( downloadLocation.isPresent() ? downloadLocation.get() : "NOASSERTION" ) + .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) .setExternalRefs( source.getExternalRefs() ) .build(); // We don't want to copy any of the properties which have other elements since it @@ -603,10 +575,9 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc * Convert a list of Maven licenses to an SPDX License * * @param mavenLicenses List of maven licenses to map - * @return - * @throws LicenseMapperException - * @throws InvalidSPDXAnalysisException - * @throws LicenseManagerException + * @return SPDX license equivalent to the list of Maven licenses + * @throws LicenseMapperException on errors accessing either the SPDX listed licenses or local extracted licenses + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private AnyLicenseInfo mavenLicensesToSpdxLicense( List mavenLicenses ) throws LicenseMapperException, InvalidSPDXAnalysisException { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java index 2b754f1..3ddf6d8 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -15,7 +15,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; -import java.util.Objects; import java.util.Set; import org.apache.maven.model.License; @@ -79,12 +78,9 @@ public class SpdxV2DocumentBuilder * @param generatePurls If true, generated Package URLs for all package references * @param spdxFile File to store the SPDX document results * @param spdxDocumentNamespace SPDX Document namespace - must be unique - * @param useStdLicenseSourceUrls if true, map any SPDX standard license source URL to license ID. Note: - * significant performance degradation - * @param outputFormatEnum + * @param outputFormatEnum output format to use for storing the SPDX file */ public SpdxV2DocumentBuilder( MavenProject mavenProject, boolean generatePurls, File spdxFile, URI spdxDocumentNamespace, - boolean useStdLicenseSourceUrls, OutputFormat outputFormatEnum ) throws SpdxBuilderException, LicenseMapperException { super( mavenProject, generatePurls, spdxFile, outputFormatEnum ); @@ -106,7 +102,7 @@ public SpdxV2DocumentBuilder( MavenProject mavenProject, boolean generatePurls, } // process the licenses - licenseManager = new SpdxV2LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + licenseManager = new SpdxV2LicenseManager( spdxDoc); } /** @@ -155,7 +151,7 @@ private Collection toSpdxAnnotations( org.spdx.maven.Annotation[] an for ( org.spdx.maven.Annotation annotation: annotations ) { - AnnotationType annotationType = AnnotationType.OTHER; + @SuppressWarnings("UnusedAssignment") AnnotationType annotationType = AnnotationType.OTHER; try { annotationType = AnnotationType.valueOf( annotation.getAnnotationType() ); @@ -183,7 +179,7 @@ private Collection toSpdxAnnotations( org.spdx.maven.Annotation[] an * Fill in the creator information to the SPDX document * * @param projectInformation project level information including the creators - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws InvalidSPDXAnalysisException { @@ -198,8 +194,7 @@ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws } else { - LOG.warn( - "Invalid creator string ( " + verify + " ), " + parameterCreator + " will be skipped." ); + LOG.warn("Invalid creator string ( {} ), {} will be skipped.", verify, parameterCreator); } } SpdxCreatorInformation spdxCreator = spdxDoc.createCreationInfo( creators, format.format( new Date() ) ); @@ -223,7 +218,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } else { - LOG.warn( "Invalid download location in POM file: " + projectInformation.getDownloadUrl() ); + LOG.warn("Invalid download location in POM file: {}", projectInformation.getDownloadUrl()); } if ( downloadUrl == null ) { @@ -232,7 +227,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation SpdxPackageVerificationCode nullPackageVerificationCode; try { - nullPackageVerificationCode = spdxDoc.createPackageVerificationCode( NULL_SHA1, new ArrayList() ); + nullPackageVerificationCode = spdxDoc.createPackageVerificationCode( NULL_SHA1, new ArrayList<>() ); } catch ( InvalidSPDXAnalysisException e ) { @@ -300,7 +295,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } catch( InvalidSPDXAnalysisException ex ) { - LOG.warn( "Invalid URL in project POM file: "+projectInformation.getHomePage() ); + LOG.warn("Invalid URL in project POM file: {}", projectInformation.getHomePage()); } } @@ -347,14 +342,14 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation { for ( Checksum checksum : projectInformation.getChecksums() ) { - final ChecksumAlgorithm algorithm = ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ); - if ( Objects.isNull( algorithm )) + try { - LOG.error( String.format( "Invalid checksum algorithm %s", checksum.getAlgorithm() ) ); + final ChecksumAlgorithm algorithm = ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ); + pkg.getChecksums().add( spdxDoc.createChecksum( algorithm, checksum.getValue() )); } - else + catch ( IllegalArgumentException | NullPointerException e1 ) { - pkg.getChecksums().add( spdxDoc.createChecksum( algorithm, checksum.getValue() )); + LOG.error("Invalid checksum algorithm {}", checksum.getAlgorithm()); } } } @@ -366,7 +361,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } // external references ExternalReference[] externalRefs = projectInformation.getExternalRefs(); - if ( externalRefs != null && externalRefs.length > 0 ) + if (externalRefs != null) { for ( ExternalReference externalRef : externalRefs ) { @@ -460,7 +455,7 @@ public void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) t public ExternalRef convertExternalRef( ExternalReference externalReference ) throws MojoExecutionException { - ReferenceCategory cat = null; + ReferenceCategory cat; try { cat = ReferenceCategory.valueOf( externalReference.getCategory().replaceAll( "-", "_" ) ); @@ -469,7 +464,7 @@ public ExternalRef convertExternalRef( ExternalReference externalReference ) thr { throw new MojoExecutionException("External reference category " + externalReference.getCategory() + " is not recognized as a valid, standard category." ); } - ReferenceType refType = null; + ReferenceType refType; try { refType = ListedReferenceTypes.getListedReferenceTypes().getListedReferenceTypeByName( externalReference.getType() ); diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java index 030b67b..0bf5cbe 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -40,6 +40,8 @@ import org.spdx.maven.SnippetInfo; import org.spdx.storage.IModelStore.IdType; +import javax.annotation.Nullable; + /** * Collects SPDX file information from directories in SPDX Spec version 2 format @@ -51,6 +53,7 @@ */ public class SpdxV2FileCollector extends AbstractFileCollector { + private static final String DEFAULT_SHA1_VALUE = "0000000000000000000000000000000000000000"; Set licensesFromFiles = new HashSet<>(); /** * Map of fileName, SPDXFile for all files in the SPDX document @@ -78,13 +81,14 @@ public SpdxV2FileCollector() * @param projectPackage Package to which the files belong * @param spdxDoc SPDX document which contains the extracted license infos that may be needed for license parsing * - * @throws SpdxCollectionException + * @throws SpdxCollectionException on incompatible types in an SPDX collection */ - public void collectFiles( List fileSets, String baseDir, - SpdxDefaultFileInformation defaultFileInformation, - Map pathSpecificInformation, - SpdxPackage projectPackage, RelationshipType relationshipType, - SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException + @SuppressWarnings("DuplicateExpressions") + public void collectFiles(List fileSets, String baseDir, + SpdxDefaultFileInformation defaultFileInformation, + Map pathSpecificInformation, + SpdxPackage projectPackage, RelationshipType relationshipType, + SpdxDocument spdxDoc, Set algorithms ) throws SpdxCollectionException { for ( FileSet fileSet : fileSets ) { @@ -118,13 +122,13 @@ public void collectFiles( List fileSets, String baseDir, /** * Find the most appropriate file information based on the lowest level match (closed to file) * - * @param filePath - * @param pathSpecificInformation - * @return + * @param filePath file path for possible file path specific information + * @param pathSpecificInformation information to be applied to the file path + * @return default SPDX parameters for a given file path or null if package level defaults are to be used */ - private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, Map pathSpecificInformation ) + private @Nullable SpdxDefaultFileInformation findDefaultFileInformation(String filePath, Map pathSpecificInformation ) { - LOG.debug( "Checking for file path " + filePath ); + LOG.debug("Checking for file path {}", filePath); SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); if ( retval != null ) { @@ -133,7 +137,7 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, } // see if any of the parent directories contain default information which should be used String parentPath = filePath; - int parentPathIndex = 0; + int parentPathIndex; do { parentPathIndex = parentPath.lastIndexOf( "/" ); @@ -145,7 +149,7 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, } while ( retval == null && parentPathIndex > 0 ); if ( retval != null ) { - LOG.debug( "Found directory containing file path for path specific information. File path: " + parentPath ); + LOG.debug("Found directory containing file path for path specific information. File path: {}", parentPath); } return retval; } @@ -153,13 +157,13 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, /** * Collect SPDX information for a specific file * - * @param file + * @param file File to collect SPDX information about * @param outputFileName Path to the output file name relative to the root of the output archive file * @param relationshipType Type of relationship to the project package * @param projectPackage Package to which the files belong * @param spdxDoc SPDX Document which will contain the files * @param algorithms algorithms to use to generate checksums - * @throws SpdxCollectionException + * @throws SpdxCollectionException on incompatible type errors in an SPDX collection */ private void collectFile( File file, String outputFileName, SpdxDefaultFileInformation fileInfo, RelationshipType relationshipType, SpdxPackage projectPackage, @@ -222,12 +226,12 @@ private void collectFile( File file, String outputFileName, SpdxDefaultFileInfor /** * Create an SpdxSnippet from the snippet information provided - * @param snippet - * @param spdxFile - * @param spdxDoc - * @return - * @throws SpdxBuilderException - * @throws InvalidSPDXAnalysisException + * @param snippet snippet to collect SPDX information about + * @param spdxFile SPDX file containing the snippet + * @param spdxDoc SPDX document containing the SPDX file + * @return SPDX Snippet based on the information collected + * @throws SpdxBuilderException on errors building the snippet + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private SpdxSnippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile, SpdxDocument spdxDoc ) throws SpdxBuilderException, InvalidSPDXAnalysisException { @@ -251,13 +255,13 @@ private SpdxSnippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile } /** - * @param file + * @param file File to be to convert to SPDX file metadata * @param outputFileName Path to the output file name relative to the root of the output archive file * @param defaultFileInformation Information on default SPDX field data for the files * @param algorithms algorithms to use to generate checksums * @param spdxDoc SPDX document which will contain the SPDX file - * @return - * @throws SpdxCollectionException + * @return SPDX file based on file and default file information + * @throws SpdxCollectionException on incompatible class types in an SPDX collection */ private SpdxFile convertToSpdxFile( File file, String outputFileName, SpdxDefaultFileInformation defaultFileInformation, @@ -276,7 +280,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { throw new SpdxCollectionException( "Unable to generate checksum for file "+file.getName() ); } - AnyLicenseInfo concludedLicense = null; + AnyLicenseInfo concludedLicense; AnyLicenseInfo license = null; String licenseComment = defaultFileInformation.getLicenseComment(); if ( isSourceFile( fileTypes ) && file.length() < SpdxSourceFileParser.MAXIMUM_SOURCE_FILE_LENGTH ) @@ -290,7 +294,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { LOG.error( "Error parsing for SPDX license ID's", ex ); } - if ( fileSpdxLicenses != null && fileSpdxLicenses.size() > 0 ) + if ( fileSpdxLicenses != null && !fileSpdxLicenses.isEmpty()) { // The file has declared licenses of the form SPDX-License-Identifier: licenseId try @@ -311,18 +315,21 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, } catch ( InvalidSPDXAnalysisException e ) { - LOG.error( "Invalid license expressions found in source file "+file.getName(), e ); + LOG.error("Invalid license expressions found in source file {}", file.getName(), e); } if ( licenseComment == null ) { licenseComment = ""; } - else if ( licenseComment.length() > 0 ) + else if ( !licenseComment.isEmpty() ) { licenseComment = licenseComment.concat( "; " ); } licenseComment = licenseComment.concat( "This file contains SPDX-License-Identifiers for " ); - licenseComment = licenseComment.concat( license.toString() ); + if ( license != null ) + { + licenseComment = licenseComment.concat( license.toString() ); + } } } if ( license == null ) @@ -353,30 +360,34 @@ else if ( licenseComment.length() > 0 ) contributors = new ArrayList<>(); } - SpdxFile retval = null; + SpdxFile retval; //TODO: Add annotation try { List seenLicenses = new ArrayList<>(); seenLicenses.add( license ); - Checksum sha1 = null; + String sha1Value = null; for ( Checksum checksum:checksums ) { if (ChecksumAlgorithm.SHA1.toString().equals( checksum.getAlgorithm() )) { - sha1 = checksum; + sha1Value = checksum.getValue(); break; } } + if ( sha1Value == null ) + { + LOG.error( "No SHA1 checksum was found for file {}", file.getName() ); + sha1Value = DEFAULT_SHA1_VALUE; + } retval = spdxDoc.createSpdxFile( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), relativePath, concludedLicense, seenLicenses, copyright, - spdxDoc.createChecksum( ChecksumAlgorithm.SHA1, sha1.getValue() ) ) + spdxDoc.createChecksum( ChecksumAlgorithm.SHA1, sha1Value ) ) .setComment( comment ) .setLicenseComments( licenseComment ) .setFileTypes( fileTypes ) .setFileContributors( contributors ) .build(); - retval.setNoticeText( notice ); } @@ -430,10 +441,7 @@ public SpdxPackageVerificationCode getVerificationCode( String spdxFilePath, Spd if ( spdxFilePath != null && spdxFiles.containsKey( spdxFilePath ) ) { Optional excludedFileName = spdxFiles.get( spdxFilePath ).getName(); - if ( excludedFileName.isPresent() ) - { - excludedFileNamesFromVerificationCode.add( excludedFileName.get() ); - } + excludedFileName.ifPresent(excludedFileNamesFromVerificationCode::add); } SpdxPackageVerificationCode verificationCode; verificationCode = calculatePackageVerificationCode( spdxFiles.values(), @@ -447,9 +455,9 @@ public SpdxPackageVerificationCode getVerificationCode( String spdxFilePath, Spd * @param spdxFiles Files used to calculate the verification code * @param excludedFileNamesFromVerificationCode List of file names to exclude * @param spdxDoc SPDX document which will contain the Package Verification Code - * @return - * @throws NoSuchAlgorithmException - * @throws InvalidSPDXAnalysisException + * @return Generated SPDX Package Verification Code + * @throws NoSuchAlgorithmException in the unlikely event the encryption algorithm could not be found + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private SpdxPackageVerificationCode calculatePackageVerificationCode( Collection spdxFiles, List excludedFileNamesFromVerificationCode, @@ -459,7 +467,7 @@ private SpdxPackageVerificationCode calculatePackageVerificationCode( Collection for ( SpdxFile file : spdxFiles ) { Optional filename = file.getName(); - if ( filename.isPresent() && includeInVerificationCode( file.getName().get(), excludedFileNamesFromVerificationCode ) ) + if ( filename.isPresent() && includeInVerificationCode( filename.get(), excludedFileNamesFromVerificationCode ) ) { fileChecksums.add( file.getSha1() ); } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java index eccbd51..a80f3f8 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java @@ -49,7 +49,7 @@ public class SpdxV2LicenseManager * SPDX document containing the license information collected. All extracted licenses are added to the SPDX * document */ - SpdxDocument spdxDoc = null; + SpdxDocument spdxDoc; /** * Maps URLs to SPDX license ID's. The SPDX licenses could be an SPDX listed license or an extracted license. @@ -66,11 +66,9 @@ public class SpdxV2LicenseManager * mapping uses the license URL to uniquely identify the licenses. * * @param spdxDoc SPDX document to add any extracted licenses - * @param useStdLicenseSourceUrls if true, map any SPDX listed license source URL to license ID. Note: significant - * performance degradation - * @throws LicenseMapperException + * @throws LicenseMapperException on errors accessing SPDX listed or local licenses */ - public SpdxV2LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUrls ) throws LicenseMapperException + public SpdxV2LicenseManager( SpdxDocument spdxDoc ) throws LicenseMapperException { this.spdxDoc = spdxDoc; initializeUrlMap(); @@ -79,7 +77,7 @@ public SpdxV2LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUr /** * Initialize the URL map from the SPDX listed licenses * - * @throws LicenseMapperException + * @throws LicenseMapperException on errors accessing SPDX listed or local licenses */ private void initializeUrlMap() throws LicenseMapperException { @@ -90,8 +88,8 @@ private void initializeUrlMap() throws LicenseMapperException * Add a non-listed license to the SPDX document. Once added, the non-listed license can be referenced by the * license ID * - * @param license - * @throws LicenseManagerException + * @param license extracted license to add + * @throws LicenseManagerException on errors accessing SPDX listed or local licenses */ public void addExtractedLicense( NonStandardLicense license ) throws LicenseManagerException { @@ -129,11 +127,9 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana if ( this.urlStringToSpdxLicenseId.containsKey( url ) ) { String oldLicenseId = urlStringToSpdxLicenseId.get( url ); - LOG.warn( - "Duplicate URL for SPDX extracted license. Replacing " + oldLicenseId + " with " - + license.getLicenseId() + " for " + url ); + LOG.warn("Duplicate URL for SPDX extracted license. Replacing {} with {} for {}", oldLicenseId, license.getLicenseId(), url); } - LOG.debug( "Adding URL mapping for non-standard license " + spdxLicense.getLicenseId() ); + LOG.debug("Adding URL mapping for non-standard license {}", spdxLicense.getLicenseId()); this.urlStringToSpdxLicenseId.put( url, spdxLicense.getLicenseId() ); } } @@ -146,8 +142,11 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana * returned. if a single license is supplied, the mapped SPDX license is returned. If multiple licenses are * supplied, a conjunctive license is returned containing all mapped SPDX licenses. * - * @return - * @throws LicenseManagerException + * @return If no licenses are supplied, SpdxNoAssertion license is + * returned. if a single license is supplied, the mapped SPDX license is returned. + * If multiple licenses are supplied, a conjunctive license is returned containing + * all mapped SPDX licenses. + * @throws LicenseManagerException on errors accessing SPDX listed or local licenses */ public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList ) throws LicenseManagerException { @@ -161,7 +160,7 @@ public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList ) { spdxLicenses.add( mavenLicenseToSpdxLicense( license ) ); } - if ( spdxLicenses.size() < 1 ) + if (spdxLicenses.isEmpty()) { return new SpdxNoAssertionLicense(); } @@ -224,9 +223,9 @@ public AnyLicenseInfo mavenLicenseToSpdxLicense( License mavenLicense ) throws L /** * Create a Maven license from the SPDX license * - * @param spdxLicense - * @return - * @throws LicenseManagerException + * @param spdxLicense SPDX license to convert + * @return a Maven license from the SPDX license + * @throws LicenseManagerException on errors accessing SPDX listed or local licenses */ public License spdxLicenseToMavenLicense( AnyLicenseInfo spdxLicense ) throws LicenseManagerException { @@ -270,9 +269,8 @@ private License spdxStdLicenseToMavenLicense( SpdxListedLicense spdxLicense ) th } if ( spdxLicense.getSeeAlso().size() > 1 ) { - LOG.warn( - "SPDX license " + spdxLicense.getLicenseId() - + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + //noinspection LoggingSimilarMessage + LOG.warn("SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", spdxLicense.getLicenseId()); } return retval; } catch ( InvalidSPDXAnalysisException e ) @@ -306,9 +304,8 @@ private License spdxNonStdLicenseToMavenLicense( ExtractedLicenseInfo spdxLicens } if ( spdxLicense.getSeeAlso().size() > 1 ) { - LOG.warn( - "SPDX license " + spdxLicense.getLicenseId() - + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + //noinspection LoggingSimilarMessage + LOG.warn("SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", spdxLicense.getLicenseId()); } return retval; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java index a453597..cc8be18 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java @@ -71,11 +71,12 @@ * @author Gary O'Neall * */ +@SuppressWarnings("LoggingSimilarMessage") public class SpdxV3DependencyBuilder extends AbstractDependencyBuilder { - private SpdxDocument spdxDoc; - private SpdxV3LicenseManager licenseManager; + private final SpdxDocument spdxDoc; + private final SpdxV3LicenseManager licenseManager; /** * @param builder The document builder @@ -101,8 +102,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { if ( !(parentPackage instanceof SpdxPackage) ) { - LOG.error( String.format( "Invalid type for parent package. Expected 'SpdxPackage', found %s", - parentPackage.getClass().getName() ) ); + LOG.error("Invalid type for parent package. Expected 'SpdxPackage', found {}", parentPackage.getClass().getName()); return; } Artifact dependency = dependencyNode.getArtifact(); @@ -110,8 +110,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); if ( relType == RelationshipType.OTHER ) { - LOG.warn( - "Could not determine the SPDX relationship type for dependency artifact ID " + dependency.getArtifactId() + " scope " + scope ); + LOG.warn( "Could not determine the SPDX relationship type for dependency artifact ID {} scope {}", dependency.getArtifactId(), scope ); } Element dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, @@ -125,7 +124,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode .setScope( scopeToLifecycleScope( scope ) ) .setComment( "Relationship created based on Maven POM information" ) .build(); - LOG.debug( "Added relationship of type " + relType + " for " + dependencyPackage.getName() ); + LOG.debug( "Added relationship of type {} for {}", relType, dependencyPackage.getName() ); if ( includeTransitiveDependencies ) { addMavenDependencies( mavenProjectBuilder, session, mavenProject, dependencyNode, dependencyPackage ); @@ -135,9 +134,9 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode /** * Translate the scope to the SPDX relationship type * - * @param scope Maven Dependency Scope (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope) + * @param scope Maven Dependency Scope (see Maven dependency scope documentation) * @param optional True if this is an optional dependency - * @return SPDX Relationship type based on the scope + * @return SPDX Relationship type based on the scope */ private RelationshipType scopeToRelationshipType( String scope, boolean optional ) { @@ -188,7 +187,6 @@ else if ( scope.equals( "test" ) ) * @param project Maven project * @param useArtifactID If true, use ${project.groupId}:${artifactId} as the SPDX package name, otherwise, ${project.name} will be used * @return SPDX Package generated from the metadata in the Maven Project - * @throws IOException On errors reading Maven file information * @throws SpdxCollectionException On errors with SPDX collections * @throws NoSuchAlgorithmException if no checksum algorithm was found * @throws LicenseMapperException on errors mapping or creating SPDX custom licenses @@ -270,7 +268,7 @@ private SpdxPackage createSpdxPackage( MavenProject project, boolean useArtifact try { retval.setHomePage( project.getUrl() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( "Invalid homepage for dependency " + project.getArtifactId() + ": " + project.getUrl() ); + LOG.warn( "Invalid homepage for dependency {}: {}", project.getArtifactId(), project.getUrl() ); } } return retval; @@ -292,14 +290,14 @@ private Element createSpdxPackage( Artifact artifact, ProjectBuilder mavenProjectBuilder, MavenSession session, MavenProject mavenProject, boolean useArtifactID ) throws LicenseMapperException, InvalidSPDXAnalysisException { - LOG.debug( "Creating SPDX package for artifact " + artifact.getArtifactId() ); + LOG.debug( "Creating SPDX package for artifact {}", artifact.getArtifactId() ); if ( artifact.getFile() == null ) { LOG.debug( "Artifact file is null" ); } else { - LOG.debug( "Artifact file name = " + artifact.getFile().getName() ); + LOG.debug( "Artifact file name = {}", artifact.getFile().getName() ); } File spdxFile = null; if ( artifact.getFile() != null ) @@ -309,12 +307,10 @@ private Element createSpdxPackage( Artifact artifact, Element retval = null; if ( spdxFile != null && spdxFile.exists() ) { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Looking for SPDX file " + spdxFile.getAbsolutePath() ); + LOG.debug( "Dependency {}Looking for SPDX file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath() ); try { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Dependency information collected from SPDX spec version 3 file " + spdxFile.getAbsolutePath() ); + LOG.debug( "Dependency {}Dependency information collected from SPDX spec version 3 file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath() ); SpdxDocument externalSpdxDoc = spdxDocumentFromFile( spdxFile.getPath() ); if ( createExternalRefs ) @@ -324,34 +320,28 @@ private Element createSpdxPackage( Artifact artifact, } else { - retval = copyPackageInfoFromExternalDoc( externalSpdxDoc, artifact.getGroupId(), - artifact.getArtifactId(), artifact.getVersion() ); + retval = copyPackageInfoFromExternalDoc( externalSpdxDoc, artifact.getArtifactId() ); } } catch ( IOException e ) { - LOG.warn( - "IO error reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "IO error reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( SpdxInvalidIdException e ) { - LOG.warn( - "Invalid SPDX ID exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Invalid SPDX ID exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( - "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( SpdxCollectionException e ) { - LOG.warn( - "Unable to create file checksum for external SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Unable to create file checksum for external SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( Exception e ) { - LOG.warn( - "Unknown error processing SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Unknown error processing SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } } if ( retval != null ) @@ -362,35 +352,28 @@ private Element createSpdxPackage( Artifact artifact, spdxFile = artifactFileToSpdxFile( artifact.getFile(), SpdxMajorVersion.VERSION_2 ); if ( spdxFile != null && spdxFile.exists() ) { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Looking for SPDX spec version 2 file " + spdxFile.getAbsolutePath() ); + LOG.debug( "Dependency {}Looking for SPDX spec version 2 file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath() ); try { - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Dependency information collected from SPDX spec version 2 file " + spdxFile.getAbsolutePath() ); + LOG.debug( "Dependency {}Dependency information collected from SPDX spec version 2 file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath() ); - retval = copyPackageInfoFromV2File( spdxFile.getPath(), artifact.getGroupId(), - artifact.getArtifactId(), artifact.getVersion() ); + retval = copyPackageInfoFromV2File( spdxFile.getPath(), artifact.getArtifactId() ); } catch ( IOException e ) { - LOG.warn( - "IO error reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "IO error reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( SpdxInvalidIdException e ) { - LOG.warn( - "Invalid SPDX ID exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Invalid SPDX ID exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( - "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } catch ( Exception e ) { - LOG.warn( - "Unknown error processing SPDX document for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() + ". Using POM file information for creating SPDX package data." ); + LOG.warn( "Unknown error processing SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage() ); } } if ( retval != null ) @@ -402,42 +385,36 @@ private Element createSpdxPackage( Artifact artifact, ProjectBuildingRequest request = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); request.setRemoteRepositories( mavenProject.getRemoteArtifactRepositories() ); for ( ArtifactRepository ar : request.getRemoteRepositories() ) { - LOG.debug( "request Remote repository ID: " + ar.getId() ); + LOG.debug( "request Remote repository ID: {}", ar.getId() ); } for ( ArtifactRepository ar : mavenProject.getRemoteArtifactRepositories() ) { - LOG.debug( "Project Remote repository ID: " + ar.getId() ); + LOG.debug( "Project Remote repository ID: {}", ar.getId() ); } ProjectBuildingResult build = mavenProjectBuilder.build( artifact, request ); MavenProject depProject = build.getProject(); - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Collecting information from project metadata for " + depProject.getArtifactId() ); + LOG.debug( "Dependency {}Collecting information from project metadata for {}", artifact.getArtifactId(), depProject.getArtifactId() ); retval = createSpdxPackage( depProject, useArtifactID ); } catch ( SpdxCollectionException e ) { - LOG.error( - "SPDX File Collection Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error( "SPDX File Collection Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage() ); } catch ( NoSuchAlgorithmException e ) { - LOG.error( - "Verification Code Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error( "Verification Code Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage() ); } catch ( ProjectBuildingException e ) { - LOG.error( - "Maven Project Build Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ":" + e.getMessage() ); + LOG.error( "Maven Project Build Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage() ); } if ( retval != null ) { return retval; } - LOG.warn( - "Error creating SPDX package for dependency artifact ID " + artifact.getArtifactId() + ". A minimal SPDX package will be created." ); + LOG.warn( "Error creating SPDX package for dependency artifact ID {}. A minimal SPDX package will be created.", artifact.getArtifactId() ); // Create a minimal SPDX package from dependency // Name will be the artifact ID - LOG.debug( - "Dependency " + artifact.getArtifactId() + "Using only artifact information to create dependent package" ); + LOG.debug( "Dependency {}Using only artifact information to create dependent package", artifact.getArtifactId() ); SpdxPackage pkg = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) .setName( artifact.getArtifactId() ) .setComment( "This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file." ) @@ -463,16 +440,14 @@ private Element createSpdxPackage( Artifact artifact, /** * Creates a copy from an SPDX version 2 file - * @param path - * @param groupId - * @param artifactId - * @param version - * @return - * @throws InvalidSPDXAnalysisException - * @throws IOException - * @throws FileNotFoundException + * @param path Path to the SPDX spec version 2 file + * @param artifactId Maven artifact ID for the file + * @return SPDX V3 compliant element for the SPDX package represented by the arttifactId in the SPDX file + * @throws InvalidSPDXAnalysisException on SPDX parsing errors + * @throws IOException on errors reading from the SPDX V2 document file + * @throws FileNotFoundException on the SPDX V2 document file not being found */ - private Element copyPackageInfoFromV2File( String path, String groupId, String artifactId, String version ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException + private Element copyPackageInfoFromV2File( String path, String artifactId ) throws FileNotFoundException, IOException, InvalidSPDXAnalysisException { org.spdx.library.model.v2.SpdxDocument v2Doc = SpdxV2DependencyBuilder.spdxDocumentFromFile( path ); org.spdx.library.model.v2.SpdxPackage source = SpdxV2DependencyBuilder.findMatchingDescribedPackage( v2Doc, artifactId ); @@ -481,9 +456,9 @@ private Element copyPackageInfoFromV2File( String path, String groupId, String a Optional name = source.getName(); SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) - .setName( name.isPresent() ? name.get() : "NONE" ) + .setName(name.orElse("NONE")) .setCopyrightText( source.getCopyrightText() != null ? source.getCopyrightText() : "NOASSERTION" ) - .setDownloadLocation( downloadLocation.isPresent() ? downloadLocation.get() : "NOASSERTION" ) + .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) .build(); Optional pvc = source.getPackageVerificationCode(); @@ -516,10 +491,12 @@ private Element copyPackageInfoFromV2File( String path, String groupId, String a .setCreationInfo( creationInfo ) .build(); } - Optional licenseListVersion = v2Doc.getCreationInfo().getLicenseListVersion(); + org.spdx.library.model.v2.license.AnyLicenseInfo v2Declared = source.getLicenseDeclared(); LicenseExpression declaredLicense = dest.createLicenseExpression( dest.getIdPrefix() + dest.getModelStore().getNextId( IdType.SpdxId ) ) - .setLicenseExpression( source.getLicenseDeclared().toString() ) + .setLicenseExpression( v2Declared == null ? "NOASSERTION" : v2Declared.toString() ) .build(); + Optional licenseListVersion = v2Doc.getCreationInfo() == null ? Optional.empty() : + v2Doc.getCreationInfo().getLicenseListVersion(); if ( licenseListVersion.isPresent() ) { declaredLicense.setLicenseListVersion( licenseListVersion.get() ); @@ -562,7 +539,7 @@ private Element copyPackageInfoFromV2File( String path, String groupId, String a } } - else if ( licenseComments.isEmpty() ) + else if ( licenseComments.isPresent() ) { dest.setComment( "License Comments: " + licenseComments.get() ); } @@ -579,7 +556,10 @@ else if ( licenseComments.isEmpty() ) Optional originator = source.getOriginator(); if ( originator.isPresent() ) { - dest.getOriginatedBys().add( Spdx2to3Converter.stringToAgent( originator.get(), dest.getCreationInfo() ) ); + // we know the creationInfo is not null since it is copied from the SPDX package when initially created + //noinspection DataFlowIssue + dest.getOriginatedBys().add( Spdx2to3Converter.stringToAgent( originator.get(), + dest.getCreationInfo() ) ); } Optional pkgFileName = source.getPackageFileName(); if ( pkgFileName.isPresent() ) @@ -623,6 +603,8 @@ else if ( licenseComments.isEmpty() ) } Optional supplier = source.getSupplier(); if ( supplier.isPresent() ) { + // we know the creationInfo is not null since it is copied from the SPDX package when initially created + //noinspection DataFlowIssue dest.setSuppliedBy( Spdx2to3Converter.stringToAgent( supplier.get(), dest.getCreationInfo() ) ); } Optional validUntil = source.getValidUntilDate(); @@ -741,7 +723,7 @@ private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundExce try ( InputStream inputStream = new FileInputStream( path ) ) { CoreModelObject root = modelStore.deSerialize( inputStream, false ); - if ( root instanceof SpdxDocument ) + if ( root != null ) { root.setCopyManager( spdxDoc.getCopyManager() ); return (SpdxDocument)root; @@ -754,15 +736,10 @@ private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundExce } finally { - if ( modelStore != null ) { - try - { - modelStore.close(); - } - catch ( Exception e ) - { - LOG.error( "Error closing SPDX model store", e ); - } + try { + modelStore.close(); + } catch (Exception e) { + LOG.error("Error closing SPDX model store", e); } } } @@ -770,23 +747,20 @@ private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundExce /** * Copies the closest matching described package in the externalSpdxDoc to the returned element * @param externalSpdxDoc SPDX document containing the described package - * @param groupId Group ID of the artifact * @param artifactId Artifact ID to search for - * @param version Version of the artifact * @return SPDX Package with values copied from the externalSpdxDoc * @throws InvalidSPDXAnalysisException on errors copying from the external document */ - private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc, String groupId, - String artifactId, String version ) throws InvalidSPDXAnalysisException + private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc, String artifactId ) throws InvalidSPDXAnalysisException { SpdxPackage source = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); Optional downloadLocation = source.getDownloadLocation(); Optional name = source.getName(); SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) - .setName( name.isPresent() ? name.get() : "NONE" ) + .setName(name.orElse("NONE")) .setCopyrightText( source.getCopyrightText().orElse( "NOASSERTION" ) ) .addAllVerifiedUsing( source.getVerifiedUsings() ) - .setDownloadLocation( downloadLocation.isPresent() ? downloadLocation.get() : "NOASSERTION" ) + .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) .addAllExternalIdentifier( source.getExternalIdentifiers() ) .addAllExternalRef( source.getExternalRefs() ) .addAllOriginatedBy( source.getOriginatedBys() ) @@ -802,7 +776,7 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc } catch ( InvalidSPDXAnalysisException e ) { - LOG.error( String.format( "Error copying relationships from SPDX file for artifact %s", artifactId ), e ); + LOG.error( "Error copying relationships from SPDX file for artifact {}", artifactId, e ); return false; } } ) @@ -921,7 +895,7 @@ else if ( root instanceof Sbom ) // If we got here, we didn't find the package in the SPDX document root or the SBOMs at the root of the SPDX document if ( firstFoundPackage != null ) { - LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in SPDX file." ); + LOG.warn( "Could not find matching artifact ID in SPDX file for {}. Using the first package found in SPDX file.", artifactId ); return firstFoundPackage; } if ( firstFoundSbom != null ) @@ -930,7 +904,7 @@ else if ( root instanceof Sbom ) { if ( sRoot instanceof SpdxPackage ) { - LOG.warn( "Could not find matching artifact ID in SPDX file for "+artifactId+". Using the first package found in Sbom." ); + LOG.warn( "Could not find matching artifact ID in SPDX file for {}. Using the first package found in Sbom.", artifactId ); return (SpdxPackage)sRoot; } } @@ -942,10 +916,9 @@ else if ( root instanceof Sbom ) * Convert a list of Maven licenses to an SPDX License * * @param mavenLicenses List of maven licenses to map - * @return - * @throws LicenseMapperException - * @throws InvalidSPDXAnalysisException - * @throws LicenseManagerException + * @return SPDX license represented by the maven license + * @throws LicenseMapperException thrown if no SPDX listed or extracted license exists with the same URL + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private AnyLicenseInfo mavenLicensesToSpdxLicense( List mavenLicenses ) throws LicenseMapperException, InvalidSPDXAnalysisException { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index 0475b81..47f471e 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -55,6 +55,8 @@ import org.spdx.storage.simple.InMemSpdxStore; import org.spdx.v3jsonldstore.JsonLDStore; +import static java.util.Objects.requireNonNull; + /** * Builder for SPDX Spec version 3 SBOMs * @@ -80,13 +82,10 @@ public class SpdxV3DocumentBuilder * @param mavenProject Maven project * @param generatePurls If true, generated Package URLs for all package references * @param spdxFile File to store the SPDX document results - * @param namespaceUri Namspace prefix for generated SPDX URIs document - must be unique - * @param useStdLicenseSourceUrls if true, map any SPDX standard license source URL to license ID. Note: - * significant performance degradation - * @param outputFormatEnum + * @param namespaceUri Namespace prefix for generated SPDX URIs document - must be unique + * @param outputFormatEnum format for the SPDX document */ public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, File spdxFile, URI namespaceUri, - boolean useStdLicenseSourceUrls, OutputFormat outputFormatEnum ) throws SpdxBuilderException, LicenseMapperException { super( mavenProject, generatePurls, spdxFile, outputFormatEnum ); @@ -115,7 +114,7 @@ public SpdxV3DocumentBuilder( MavenProject mavenProject, boolean generatePurls, } // process the licenses - licenseManager = new SpdxV3LicenseManager( spdxDoc, useStdLicenseSourceUrls ); + licenseManager = new SpdxV3LicenseManager( spdxDoc ); // TODO: if we want to support external custom licenses, we will need to add dictionary entries // to the customIdToUri } @@ -170,7 +169,7 @@ private void addSpdxAnnotations( org.spdx.maven.Annotation[] annotations, Elemen for ( org.spdx.maven.Annotation annotation: annotations ) { - AnnotationType annotationType = AnnotationType.OTHER; + AnnotationType annotationType; try { annotationType = Spdx2to3Converter.ANNOTATION_TYPE_MAP.get( @@ -209,11 +208,12 @@ private void addSpdxAnnotations( org.spdx.maven.Annotation[] annotations, Elemen * Fill in the creator information to the SPDX document * * @param projectInformation project level information including the creators - * @throws InvalidSPDXAnalysisException + * @throws InvalidSPDXAnalysisException on SPDX parsing errors */ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws InvalidSPDXAnalysisException { CreationInfo creationInfo = spdxDoc.getCreationInfo(); + requireNonNull( creationInfo, "CreationInfo for the SPDX document must not be null" ); String[] parameterCreators = projectInformation.getCreators(); for ( String parameterCreator : parameterCreators ) { @@ -233,8 +233,7 @@ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws } catch (InvalidSPDXAnalysisException e) { - LOG.warn( - "Invalid creator string, " + parameterCreator + " will be skipped." ); + LOG.warn( "Invalid creator string, {} will be skipped.", parameterCreator ); } } @@ -336,7 +335,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation final HashAlgorithm algorithm = Spdx2to3Converter.HASH_ALGORITH_MAP.get( ChecksumAlgorithm.valueOf( checksum.getAlgorithm() ) ); if ( Objects.isNull( algorithm )) { - LOG.error( String.format( "Invalid checksum algorithm %s", checksum.getAlgorithm() ) ); + LOG.error( "Invalid checksum algorithm {}", checksum.getAlgorithm() ); } else { @@ -370,7 +369,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } catch( InvalidSPDXAnalysisException ex ) { - LOG.warn( "Invalid URL in project POM file: "+projectInformation.getHomePage() ); + LOG.warn( "Invalid URL in project POM file: {}", projectInformation.getHomePage() ); } } @@ -387,6 +386,8 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation // originator if ( projectInformation.getOriginator() != null ) { + // creationInfo can not be null due to the builder implementation in the SPDX core package + //noinspection DataFlowIssue pkg.getOriginatedBys().add( Spdx2to3Converter.stringToAgent( projectInformation.getOriginator(), pkg.getCreationInfo() ) ); } // short description @@ -397,6 +398,8 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation // supplier if ( projectInformation.getSupplier() != null ) { + // creationInfo can not be null due to the builder implementation in the SPDX core package + //noinspection DataFlowIssue pkg.setSuppliedBy( Spdx2to3Converter.stringToAgent( projectInformation.getSupplier(), pkg.getCreationInfo() ) ); } // version info @@ -436,7 +439,7 @@ private void addExternalRefs( ExternalReference[] externalRefs, SoftwareArtifact } for ( ExternalReference externalRef : externalRefs ) { - ReferenceCategory cat = null; + ReferenceCategory cat; try { cat = ReferenceCategory.valueOf( externalRef.getCategory().replaceAll( "-", "_" ) ); @@ -445,7 +448,7 @@ private void addExternalRefs( ExternalReference[] externalRefs, SoftwareArtifact { throw new MojoExecutionException("External reference category " + externalRef.getCategory() + " is not recognized as a valid, standard category." ); } - ReferenceType refType = null; + ReferenceType refType; try { refType = ListedReferenceTypes.getListedReferenceTypes().getListedReferenceTypeByName( externalRef.getType() ); diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java index faa3062..9b43024 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java @@ -91,7 +91,7 @@ public class SpdxV3FileCollector extends AbstractFileCollector FileSetManager fileSetManager = new FileSetManager(); - private List customIdToUri; + private final List customIdToUri; /** * SpdxFileCollector collects SPDX file information for files @@ -114,7 +114,7 @@ public SpdxV3FileCollector( List customIdToUri) * @param projectPackage Package to which the files belong * @param spdxDoc SPDX document which contains the extracted license infos that may be needed for license parsing * - * @throws SpdxCollectionException + * @throws SpdxCollectionException on incompatible types in an SPDX collection */ public void collectFiles( List fileSets, String baseDir, SpdxDefaultFileInformation defaultFileInformation, @@ -154,13 +154,13 @@ public void collectFiles( List fileSets, String baseDir, /** * Find the most appropriate file information based on the lowest level match (closed to file) * - * @param filePath - * @param pathSpecificInformation - * @return + * @param filePath file path for possible file path specific information + * @param pathSpecificInformation information to be applied to the file path + * @return default SPDX parameters for a given file path or null if package level defaults are to be used */ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, Map pathSpecificInformation ) { - LOG.debug( "Checking for file path " + filePath ); + LOG.debug( "Checking for file path {}", filePath ); SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); if ( retval != null ) { @@ -169,7 +169,7 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, } // see if any of the parent directories contain default information which should be used String parentPath = filePath; - int parentPathIndex = 0; + int parentPathIndex; do { parentPathIndex = parentPath.lastIndexOf( "/" ); @@ -181,7 +181,7 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, } while ( retval == null && parentPathIndex > 0 ); if ( retval != null ) { - LOG.debug( "Found directory containing file path for path specific information. File path: " + parentPath ); + LOG.debug( "Found directory containing file path for path specific information. File path: {}", parentPath ); } return retval; } @@ -189,13 +189,13 @@ private SpdxDefaultFileInformation findDefaultFileInformation( String filePath, /** * Collect SPDX information for a specific file * - * @param file + * @param file File to collect SPDX information for * @param outputFileName Path to the output file name relative to the root of the output archive file * @param relationshipType Type of relationship to the project package * @param projectPackage Package to which the files belong * @param spdxDoc SPDX Document which will contain the files * @param algorithms algorithms to use to generate checksums - * @throws SpdxCollectionException + * @throws SpdxCollectionException on incompatible types in an SPDX collection */ private void collectFile( File file, String outputFileName, SpdxDefaultFileInformation fileInfo, RelationshipType relationshipType, SpdxPackage projectPackage, @@ -306,13 +306,13 @@ private Snippet convertToSpdxSnippet( SnippetInfo snippet, SpdxFile spdxFile ) t } /** - * @param file + * @param file File to convert to an SPDX file from * @param outputFileName Path to the output file name relative to the root of the output archive file * @param defaultFileInformation Information on default SPDX field data for the files * @param algorithms algorithms to use to generate checksums * @param spdxDoc SPDX document which will contain the SPDX file - * @return - * @throws SpdxCollectionException + * @return SPDX file based on file and default file information + * @throws SpdxCollectionException on incompatible class types in an SPDX collection */ private SpdxFile convertToSpdxFile( File file, String outputFileName, SpdxDefaultFileInformation defaultFileInformation, @@ -344,7 +344,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { throw new SpdxCollectionException( "Unable to generate checksum for file "+file.getName() ); } - AnyLicenseInfo concludedLicense = null; + AnyLicenseInfo concludedLicense; AnyLicenseInfo license = null; String licenseComment = defaultFileInformation.getLicenseComment(); if ( SoftwarePurpose.SOURCE.equals( purpose ) && file.length() < SpdxSourceFileParser.MAXIMUM_SOURCE_FILE_LENGTH ) @@ -358,7 +358,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { LOG.error( "Error parsing for SPDX license ID's", ex ); } - if ( fileSpdxLicenses != null && fileSpdxLicenses.size() > 0 ) + if ( fileSpdxLicenses != null && !fileSpdxLicenses.isEmpty() ) { // The file has declared licenses of the form SPDX-License-Identifier: licenseId try @@ -381,18 +381,21 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, } catch ( InvalidSPDXAnalysisException e ) { - LOG.error( "Invalid license expressions found in source file "+file.getName(), e ); + LOG.error( "Invalid license expressions found in source file {}", file.getName(), e ); } if ( licenseComment == null ) { licenseComment = ""; } - else if ( licenseComment.length() > 0 ) + else if ( !licenseComment.isEmpty() ) { licenseComment = licenseComment.concat( "; " ); } licenseComment = licenseComment.concat( "This file contains SPDX-License-Identifiers for " ); - licenseComment = licenseComment.concat( license.toString() ); + if ( license != null ) + { + licenseComment = licenseComment.concat( license.toString() ); + } } } if ( license == null ) @@ -439,7 +442,7 @@ else if ( licenseComment.length() > 0 ) } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn( "Error creating contributor "+contributor+" for file "+file+". Skipping." ); + LOG.warn( "Error creating contributor {} for file {}. Skipping.", contributor, file ); } } } @@ -447,7 +450,7 @@ else if ( licenseComment.length() > 0 ) contributors = new ArrayList<>(); } - SpdxFile retval = null; + SpdxFile retval; //TODO: Add annotation try { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java index 870ad11..1356bb8 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3LicenseManager.java @@ -51,7 +51,7 @@ public class SpdxV3LicenseManager * SPDX document containing the license information collected. All extracted licenses are added to the SPDX * document */ - SpdxDocument spdxDoc = null; + SpdxDocument spdxDoc; /** * Maps URLs to SPDX license ID's. The SPDX licenses could be an SPDX listed license or an extracted license. @@ -68,11 +68,9 @@ public class SpdxV3LicenseManager * mapping uses the license URL to uniquely identify the licenses. * * @param spdxDoc SPDX document to add any extracted licenses - * @param useStdLicenseSourceUrls if true, map any SPDX listed license source URL to license ID. Note: significant - * performance degradation - * @throws LicenseMapperException + * @throws LicenseMapperException on errors accessing SPDX listed or local licenses */ - public SpdxV3LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUrls ) throws LicenseMapperException + public SpdxV3LicenseManager( SpdxDocument spdxDoc ) throws LicenseMapperException { this.spdxDoc = spdxDoc; initializeUrlMap(); @@ -81,7 +79,7 @@ public SpdxV3LicenseManager( SpdxDocument spdxDoc, boolean useStdLicenseSourceUr /** * Initialize the URL map from the SPDX listed licenses * - * @throws LicenseMapperException + * @throws LicenseMapperException on errors accessing SPDX listed or local licenses */ private void initializeUrlMap() throws LicenseMapperException { @@ -92,8 +90,8 @@ private void initializeUrlMap() throws LicenseMapperException * Add a non-listed license to the SPDX document. Once added, the non-listed license can be referenced by the * license ID * - * @param license - * @throws LicenseManagerException + * @param license license to add to extracted license map + * @throws LicenseManagerException on errors accessing SPDX listed or local licenses */ public void addExtractedLicense( NonStandardLicense license ) throws LicenseManagerException { @@ -128,11 +126,9 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana if ( this.urlStringToSpdxLicenseId.containsKey( url ) ) { String oldLicenseId = urlStringToSpdxLicenseId.get( url ); - LOG.warn( - "Duplicate URL for SPDX extracted license. Replacing " + oldLicenseId + " with " - + license.getLicenseId() + " for " + url ); + LOG.warn( "Duplicate URL for SPDX extracted license. Replacing {} with {} for {}", oldLicenseId, license.getLicenseId(), url ); } - LOG.debug( "Adding URL mapping for non-standard license " + license.getLicenseId() ); + LOG.debug( "Adding URL mapping for non-standard license {}", license.getLicenseId() ); this.urlStringToSpdxLicenseId.put( url, license.getLicenseId() ); } } @@ -145,8 +141,11 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana * returned. if a single license is supplied, the mapped SPDX license is returned. If multiple licenses are * supplied, a conjunctive license is returned containing all mapped SPDX licenses. * - * @return - * @throws LicenseManagerException + * @return If no licenses are supplied, SpdxNoAssertion license is + * returned. if a single license is supplied, the mapped SPDX license is returned. + * If multiple licenses are supplied, a conjunctive license is returned containing + * all mapped SPDX licenses. + * @throws LicenseManagerException on errors accessing SPDX listed or local licenses */ public AnyLicenseInfo mavenLicenseListToSpdxLicense( List licenseList ) throws LicenseManagerException { @@ -221,9 +220,9 @@ public AnyLicenseInfo mavenLicenseToSpdxLicense( License mavenLicense ) throws L /** * Create a Maven license from the SPDX license * - * @param spdxLicense - * @return - * @throws LicenseManagerException + * @param spdxLicense source SPDX license to convert + * @return a Maven license from the SPDX license + * @throws LicenseManagerException thrown if no SPDX listed or extracted license exists with the same UR */ public License spdxLicenseToMavenLicense( AnyLicenseInfo spdxLicense ) throws LicenseManagerException { @@ -267,9 +266,7 @@ private License spdxStdLicenseToMavenLicense( ListedLicense spdxLicense ) throws } if ( spdxLicense.getSeeAlsos().size() > 1 ) { - LOG.warn( - "SPDX license " + SpdxListedLicenseModelStore.objectUriToLicenseOrExceptionId( spdxLicense.getObjectUri() ) - + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + LOG.warn( "SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", SpdxListedLicenseModelStore.objectUriToLicenseOrExceptionId( spdxLicense.getObjectUri() ) ); } return retval; } catch ( InvalidSPDXAnalysisException e ) @@ -284,7 +281,8 @@ private License spdxNonStdLicenseToMavenLicense( CustomLicense spdxLicense ) thr { License retval = new License(); // license ID - String licenseId = spdxLicense.getObjectUri().substring( spdxLicense.getIdPrefix().length() ); + int prefixLen = spdxLicense.getIdPrefix() == null ? 0 : spdxLicense.getIdPrefix().length(); + String licenseId = spdxLicense.getObjectUri().substring( prefixLen ); // name if ( spdxLicense.getName().isPresent() && !spdxLicense.getName().get().isEmpty() ) { @@ -305,9 +303,7 @@ private License spdxNonStdLicenseToMavenLicense( CustomLicense spdxLicense ) thr } if ( spdxLicense.getSeeAlsos().size() > 1 ) { - LOG.warn( - "SPDX license " + licenseId - + " contains multiple URLs. Only the first URL will be preserved in the Maven license created." ); + LOG.warn( "SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", licenseId ); } return retval; } diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java b/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java index 1d822cc..57dd487 100644 --- a/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV2LicenseManager.java @@ -104,7 +104,7 @@ public void tearDown() throws Exception public void testLicenseManager() throws LicenseMapperException { @SuppressWarnings( "unused" ) - SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc); } /** @@ -118,7 +118,7 @@ public void testLicenseManager() throws LicenseMapperException @Test public void testAddNonStandardLicense() throws MalformedURLException, LicenseManagerException, InvalidSPDXAnalysisException, LicenseMapperException { - SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc); NonStandardLicense lic = new NonStandardLicense(); final String COMMENT = "comment"; final String[] CROSS_REF_STR = new String[] {"http://www.licenseRef1", "http://www.licenseref2"}; @@ -186,7 +186,7 @@ public void testMavenLicenseListToSpdxLicense() throws LicenseManagerException, licenseList.add( apache ); licenseList.add( apsl ); - SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, true ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc); AnyLicenseInfo result = licenseManager.mavenLicenseListToSpdxLicense( licenseList ); assertTrue( result instanceof ConjunctiveLicenseSet ); @@ -226,7 +226,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf License apache = new License(); apache.setName( LICENSE1_NAME ); apache.setUrl( APACHE_CROSS_REF_URL2 ); - SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, true ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc); AnyLicenseInfo result = licenseManager.mavenLicenseToSpdxLicense( apache ); assertTrue( result instanceof SpdxListedLicense ); @@ -271,7 +271,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf @Test public void testSpdxLicenseToMavenLicense() throws LicenseManagerException, LicenseMapperException, InvalidSPDXAnalysisException { - SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc, false ); + SpdxV2LicenseManager licenseManager = new SpdxV2LicenseManager( spdxDoc); // standard license AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( APACHE_LICENSE_ID ); License result = licenseManager.spdxLicenseToMavenLicense( licenseInfo ); diff --git a/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java b/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java index 60da92f..8e45eda 100644 --- a/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java +++ b/src/test/java/org/spdx/maven/utils/TestSpdxV3LicenseManager.java @@ -108,7 +108,7 @@ public void tearDown() throws Exception public void testLicenseManager() throws LicenseMapperException { @SuppressWarnings( "unused" ) - SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc ); } /** @@ -123,7 +123,7 @@ public void testLicenseManager() throws LicenseMapperException @Test public void testAddNonStandardLicense() throws MalformedURLException, LicenseManagerException, InvalidSPDXAnalysisException, LicenseMapperException { - SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc ); NonStandardLicense lic = new NonStandardLicense(); final String COMMENT = "comment"; final String[] CROSS_REF_STR = new String[] {"http://www.licenseRef1", "http://www.licenseref2"}; @@ -197,7 +197,7 @@ public void testMavenLicenseListToSpdxLicense() throws LicenseManagerException, licenseList.add( apache ); licenseList.add( apsl ); - SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, true ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc ); AnyLicenseInfo result = licenseManager.mavenLicenseListToSpdxLicense( licenseList ); assertTrue( result instanceof ConjunctiveLicenseSet ); @@ -237,7 +237,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf License apache = new License(); apache.setName( LICENSE1_NAME ); apache.setUrl( APACHE_CROSS_REF_URL2 ); - SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, true ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc ); AnyLicenseInfo result = licenseManager.mavenLicenseToSpdxLicense( apache ); assertTrue( result instanceof ListedLicense ); @@ -282,7 +282,7 @@ public void testMavenLicenseToSpdxLicense() throws LicenseManagerException, Malf @Test public void testSpdxLicenseToMavenLicense() throws LicenseManagerException, LicenseMapperException, InvalidSPDXAnalysisException { - SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc, false ); + SpdxV3LicenseManager licenseManager = new SpdxV3LicenseManager( spdxDoc ); // standard license AnyLicenseInfo licenseInfo = LicenseInfoFactory.parseSPDXLicenseString( APACHE_LICENSE_ID ); License result = licenseManager.spdxLicenseToMavenLicense( licenseInfo ); From 121f0becb10506483885f4390d7191a0c366ba54 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sun, 15 Dec 2024 15:35:23 -0800 Subject: [PATCH 09/10] Always pass in modelstore to expression parser Since we're not initializing or using the default model store, we need to always pass in a model store to the license expression parser methods. Note that not using the default avoids a potential memory issue for long running Maven scripts. --- .../spdx/maven/utils/SpdxV2FileCollector.java | 20 +++++++++++++++---- .../spdx/maven/utils/SpdxV3FileCollector.java | 12 +++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java index 0bf5cbe..91e909d 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -301,14 +301,20 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { if ( fileSpdxLicenses.size() == 1 ) { - license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( fileSpdxLicenses.get( 0 ) ); + license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( fileSpdxLicenses.get( 0 ), + spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ); } else { Set licenseSet = new HashSet<>(); for ( String licenseExpression : fileSpdxLicenses ) { - licenseSet.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( licenseExpression ) ); + licenseSet.add( LicenseInfoFactory.parseSPDXLicenseStringCompatV2( licenseExpression, + spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ) ); } license = spdxDoc.createConjunctiveLicenseSet( licenseSet ); } @@ -336,8 +342,14 @@ else if ( !licenseComment.isEmpty() ) { try { - license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getDeclaredLicense() ); - concludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getConcludedLicense() ); + license = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getDeclaredLicense(), + spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ); + concludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2( defaultFileInformation.getConcludedLicense(), + spdxDoc.getModelStore(), + spdxDoc.getDocumentUri(), + spdxDoc.getCopyManager() ); } catch ( InvalidSPDXAnalysisException e ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java index 9b43024..7a73f2e 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3FileCollector.java @@ -365,14 +365,16 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, { if ( fileSpdxLicenses.size() == 1 ) { - license = LicenseInfoFactory.parseSPDXLicenseString( fileSpdxLicenses.get( 0 ) ); + license = LicenseInfoFactory.parseSPDXLicenseString( fileSpdxLicenses.get( 0 ), + spdxDoc.getModelStore(), spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ); } else { Set licenseSet = new HashSet<>(); for ( String licenseExpression : fileSpdxLicenses ) { - licenseSet.add( LicenseInfoFactory.parseSPDXLicenseString( licenseExpression ) ); + licenseSet.add( LicenseInfoFactory.parseSPDXLicenseString( licenseExpression, + spdxDoc.getModelStore(), spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ) ); } license = spdxDoc.createConjunctiveLicenseSet( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) .addAllMember( licenseSet ) @@ -402,8 +404,10 @@ else if ( !licenseComment.isEmpty() ) { try { - license = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getDeclaredLicense() ); - concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getConcludedLicense() ); + license = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getDeclaredLicense(), + spdxDoc.getModelStore(), spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ); + concludedLicense = LicenseInfoFactory.parseSPDXLicenseString( defaultFileInformation.getConcludedLicense(), + spdxDoc.getModelStore(), spdxDoc.getIdPrefix(), spdxDoc.getCopyManager(), customIdToUri ); } catch ( InvalidSPDXAnalysisException e ) { From fa3a9481e16513a731850a93b00d12c10a35549f Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sun, 15 Dec 2024 15:53:56 -0800 Subject: [PATCH 10/10] Clean up formatting Cleaning up formatting - my IDE now has the Maven coding style added for this project, so it should be a bit cleaner going forward. --- .../utils/AbstractDependencyBuilder.java | 2 +- .../maven/utils/AbstractFileCollector.java | 6 +- .../utils/SpdxDefaultFileInformation.java | 14 ++-- .../maven/utils/SpdxExternalRefBuilder.java | 2 +- .../maven/utils/SpdxProjectInformation.java | 37 +++++----- .../maven/utils/SpdxV2DependencyBuilder.java | 70 +++++++++++-------- .../maven/utils/SpdxV2DocumentBuilder.java | 10 +-- .../spdx/maven/utils/SpdxV2FileCollector.java | 7 +- .../maven/utils/SpdxV2LicenseManager.java | 13 ++-- .../maven/utils/SpdxV3DependencyBuilder.java | 13 ++-- .../maven/utils/SpdxV3DocumentBuilder.java | 3 +- 11 files changed, 99 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java index 04b0a9b..3ea9153 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java @@ -156,7 +156,7 @@ private void logDependencies( List dependencies ) Artifact dependency = node.getArtifact(); String filePath = dependency.getFile() != null ? dependency.getFile().getAbsolutePath() : "[NONE]"; String scope = dependency.getScope() != null ? dependency.getScope() : "[NONE]"; - LOG.debug("ArtifactId: {}, file path: {}, Scope: {}", dependency.getArtifactId(), filePath, scope); + LOG.debug( "ArtifactId: {}, file path: {}, Scope: {}", dependency.getArtifactId(), filePath, scope ); } } diff --git a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java index 944d832..f61234d 100644 --- a/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java +++ b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java @@ -79,16 +79,16 @@ private static void loadFileExtensionConstants() for (Entry entry : prop.entrySet()) { String fileTypeStr = (String) entry.getKey(); FileType fileType = FileType.valueOf(fileTypeStr); - String[] extensions = ((String) entry.getValue()).split(","); + String[] extensions = ((String) entry.getValue()).split( "," ); for (String extension : extensions) { try { String trimmedExtension = extension.toUpperCase().trim(); if (EXT_TO_FILE_TYPE.containsKey(trimmedExtension)) { - LOG.warn("Duplicate file extension: {}", trimmedExtension); + LOG.warn( "Duplicate file extension: {}", trimmedExtension ); } EXT_TO_FILE_TYPE.put(trimmedExtension, fileType); } catch (Exception ex) { - LOG.error("Error adding file extensions to filetype map", ex); + LOG.error( "Error adding file extensions to filetype map", ex ); } } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java index 5fc5120..ed32e7a 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDefaultFileInformation.java @@ -139,17 +139,17 @@ public void setSnippets( List snippets ) */ public void logInfo() { - LOG.debug("Default File Comment: {}", getComment()); - LOG.debug("Default File Copyright: {}", getCopyright()); - LOG.debug("Default File License Comment: {}", getLicenseComment()); - LOG.debug("Default File Notice: {}", getNotice()); - LOG.debug("Default File Concluded License: {}", getConcludedLicense()); - LOG.debug("Default File Declared License: {}", getDeclaredLicense()); + LOG.debug( "Default File Comment: {}", getComment() ); + LOG.debug( "Default File Copyright: {}", getCopyright() ); + LOG.debug( "Default File License Comment: {}", getLicenseComment() ); + LOG.debug( "Default File Notice: {}", getNotice() ); + LOG.debug( "Default File Concluded License: {}", getConcludedLicense() ); + LOG.debug( "Default File Declared License: {}", getDeclaredLicense() ); if ( contributors != null ) { for ( String contributor : contributors ) { - LOG.debug("Default File Contributors: {}", contributor); + LOG.debug( "Default File Contributors: {}", contributor ); } } if ( this.snippets != null ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java index d27b4e1..7b1b9b2 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java @@ -31,7 +31,7 @@ private static ExternalRef generatePurlV2ExternalRef( SpdxDocument spdxDoc, try { return spdxDoc.createExternalRef( ReferenceCategory.PACKAGE_MANAGER, - new ReferenceType("http://spdx.org/rdf/references/purl"), + new ReferenceType( "http://spdx.org/rdf/references/purl" ), generatePurl( project ), null ); } catch ( InvalidSPDXAnalysisException e ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java index bbad242..69d0d89 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxProjectInformation.java @@ -338,21 +338,21 @@ public void logInfo() if ( !LOG.isDebugEnabled() ) { return; } - LOG.debug("SPDX Project Name: {}", this.getName()); - LOG.debug("SPDX Document comment: {}", this.getDocumentComment()); - LOG.debug("SPDX Creator comment: {}", this.getCreatorComment()); - LOG.debug("SPDX Description: {}", this.getDescription()); - LOG.debug("SPDX License comment: {}", this.getLicenseComment()); - LOG.debug("SPDX Originator: {}", this.getOriginator()); - LOG.debug("SPDX PackageArchiveFileName: {}", this.getPackageArchiveFileName()); - LOG.debug("SPDX Short description: {}", this.getShortDescription()); - LOG.debug("SPDX Supplier: {}", this.getSupplier()); - LOG.debug("SPDX Source Info: {}", this.getSourceInfo()); - LOG.debug("SPDX Version info: {}", this.getVersionInfo()); - LOG.debug("SPDX Concluded license: {}", this.getConcludedLicense()); - LOG.debug("SPDX Declared license: {}", this.getDeclaredLicense()); - LOG.debug("SPDX Download URL: {}", this.getDownloadUrl()); - LOG.debug("SPDX Home page: {}", this.getHomePage()); + LOG.debug( "SPDX Project Name: {}", this.getName() ); + LOG.debug( "SPDX Document comment: {}", this.getDocumentComment() ); + LOG.debug( "SPDX Creator comment: {}", this.getCreatorComment() ); + LOG.debug( "SPDX Description: {}", this.getDescription() ); + LOG.debug( "SPDX License comment: {}", this.getLicenseComment() ); + LOG.debug( "SPDX Originator: {}", this.getOriginator() ); + LOG.debug( "SPDX PackageArchiveFileName: {}", this.getPackageArchiveFileName() ); + LOG.debug( "SPDX Short description: {}", this.getShortDescription() ); + LOG.debug( "SPDX Supplier: {}", this.getSupplier() ); + LOG.debug( "SPDX Source Info: {}", this.getSourceInfo() ); + LOG.debug( "SPDX Version info: {}", this.getVersionInfo() ); + LOG.debug( "SPDX Concluded license: {}", this.getConcludedLicense() ); + LOG.debug( "SPDX Declared license: {}", this.getDeclaredLicense() ); + LOG.debug( "SPDX Download URL: {}", this.getDownloadUrl() ); + LOG.debug( "SPDX Home page: {}", this.getHomePage() ); if ( this.documentAnnotations != null && this.documentAnnotations.length > 0 ) { LOG.debug( "Document annotations: " ); @@ -373,21 +373,22 @@ public void logInfo() { for ( String creator : creators ) { - LOG.debug("SPDX Creator: {}", creator); + LOG.debug( "SPDX Creator: {}", creator ); } } if ( this.externalRefs != null ) { for ( ExternalReference externalReference : externalRefs ) { - LOG.debug("External Ref: {} {} {}", externalReference.getCategory(), externalReference.getType(), externalReference.getLocator()); + LOG.debug( "External Ref: {} {} {}", externalReference.getCategory(), + externalReference.getType(), externalReference.getLocator() ); } } if ( checksums != null && !checksums.isEmpty()) { for ( Checksum checksum : checksums ) { - LOG.debug("SPDX {}: {}", checksum.getAlgorithm(), checksum.getValue()); + LOG.debug( "SPDX {}: {}", checksum.getAlgorithm(), checksum.getValue() ); } } } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java index f8101b9..76c1956 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DependencyBuilder.java @@ -100,7 +100,7 @@ protected static SpdxDocument spdxDocumentFromFile( String path ) throws FileNot try { modelStore.close(); } catch (Exception e) { - LOG.error("Error closing SPDX model store", e); + LOG.error( "Error closing SPDX model store", e ); } } } @@ -127,7 +127,7 @@ protected static SpdxPackage findMatchingDescribedPackage( SpdxDocument external } if ( itemDescribed == null ) { // Find the first package - LOG.warn("Could not find matching artifact ID in SPDX file for {}. Using the first package found in SPDX file.", artifactId); + LOG.warn( "Could not find matching artifact ID in SPDX file for {}. Using the first package found in SPDX file.", artifactId ); for ( SpdxElement item : externalSpdxDoc.getDocumentDescribes() ) { if ( item instanceof SpdxPackage ) @@ -174,7 +174,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { if ( !(parentPackage instanceof SpdxPackage) ) { - LOG.error("Invalid type for parent package. Expected 'SpdxPackage', found {}", parentPackage.getClass().getName()); + LOG.error( "Invalid type for parent package. Expected 'SpdxPackage', found {}", parentPackage.getClass().getName() ); return; } Artifact dependency = dependencyNode.getArtifact(); @@ -182,7 +182,7 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode RelationshipType relType = scopeToRelationshipType( scope, dependency.isOptional() ); if ( relType == RelationshipType.OTHER ) { - LOG.warn("Could not determine the SPDX relationship type for dependency artifact ID {} scope {}", dependency.getArtifactId(), scope); + LOG.warn( "Could not determine the SPDX relationship type for dependency artifact ID {} scope {}", dependency.getArtifactId(), scope ); } SpdxElement dependencyPackage = createSpdxPackage( dependency, mavenProjectBuilder, session, @@ -194,13 +194,14 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { ((SpdxPackage)parentPackage).addRelationship( spdxDoc.createRelationship( dependencyPackage, relType, "Relationship created based on Maven POM information" ) ); - LOG.debug("Added relationship of type {} for {}", relType, dependencyPackage.getName()); + LOG.debug( "Added relationship of type {} for {}", relType, dependencyPackage.getName() ); } else { ((SpdxPackage)parentPackage).addRelationship(spdxDoc.createRelationship( (SpdxPackage)parentPackage, RelationshipType.OTHER, "This relationship is the inverse of " + relType + " to an external document reference." ) ); - LOG.debug("Could not create proper to relationships for external element {}", dependencyPackage.getId()); + LOG.debug( "Could not create proper to relationships for external element {}", + dependencyPackage.getId() ); } } else @@ -311,7 +312,7 @@ packageName, new SpdxNoAssertionLicense(), copyright, declaredLicense ) try { retval.setHomepage( project.getUrl() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn("Invalid homepage for dependency {}: {}", project.getArtifactId(), project.getUrl()); + LOG.warn( "Invalid homepage for dependency {}: {}", project.getArtifactId(), project.getUrl() ); } } return retval; @@ -333,14 +334,14 @@ private SpdxElement createSpdxPackage( Artifact artifact, ProjectBuilder mavenProjectBuilder, MavenSession session, MavenProject mavenProject, boolean useArtifactID ) throws LicenseMapperException, InvalidSPDXAnalysisException { - LOG.debug("Creating SPDX package for artifact {}", artifact.getArtifactId()); + LOG.debug( "Creating SPDX package for artifact {}", artifact.getArtifactId() ); if ( artifact.getFile() == null ) { LOG.debug( "Artifact file is null" ); } else { - LOG.debug("Artifact file name = {}", artifact.getFile().getName()); + LOG.debug( "Artifact file name = {}", artifact.getFile().getName() ); } File spdxFile = null; if ( artifact.getFile() != null ) @@ -349,10 +350,12 @@ private SpdxElement createSpdxPackage( Artifact artifact, } if ( spdxFile != null && spdxFile.exists() ) { - LOG.debug("Dependency {}Looking for SPDX file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath()); + LOG.debug( "Dependency {}Looking for SPDX file {}", artifact.getArtifactId(), + spdxFile.getAbsolutePath() ); try { - LOG.debug("Dependency {}Dependency information collected from SPDX file {}", artifact.getArtifactId(), spdxFile.getAbsolutePath()); + LOG.debug( "Dependency {}Dependency information collected from SPDX file {}", + artifact.getArtifactId(), spdxFile.getAbsolutePath() ); SpdxDocument externalSpdxDoc = spdxDocumentFromFile( spdxFile.getPath() ); if ( createExternalRefs ) @@ -367,23 +370,28 @@ private SpdxElement createSpdxPackage( Artifact artifact, } catch ( IOException e ) { - LOG.warn("IO error reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); + LOG.warn( "IO error reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", + artifact.getArtifactId(), e.getMessage() ); } catch ( SpdxInvalidIdException e ) { - LOG.warn("Invalid SPDX ID exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); + LOG.warn( "Invalid SPDX ID exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", + artifact.getArtifactId(), e.getMessage() ); } catch ( InvalidSPDXAnalysisException e ) { - LOG.warn("Invalid SPDX analysis exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); + LOG.warn( "Invalid SPDX analysis exception reading SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", + artifact.getArtifactId(), e.getMessage() ); } catch ( SpdxCollectionException e ) { - LOG.warn("Unable to create file checksum for external SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); + LOG.warn( "Unable to create file checksum for external SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", + artifact.getArtifactId(), e.getMessage() ); } catch ( Exception e ) { - LOG.warn("Unknown error processing SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", artifact.getArtifactId(), e.getMessage()); + LOG.warn( "Unknown error processing SPDX document for dependency artifact ID {}:{}. Using POM file information for creating SPDX package data.", + artifact.getArtifactId(), e.getMessage() ); } } try @@ -391,32 +399,38 @@ private SpdxElement createSpdxPackage( Artifact artifact, ProjectBuildingRequest request = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); request.setRemoteRepositories( mavenProject.getRemoteArtifactRepositories() ); for ( ArtifactRepository ar : request.getRemoteRepositories() ) { - LOG.debug("request Remote repository ID: {}", ar.getId()); + LOG.debug( "request Remote repository ID: {}", ar.getId() ); } for ( ArtifactRepository ar : mavenProject.getRemoteArtifactRepositories() ) { - LOG.debug("Project Remote repository ID: {}", ar.getId()); + LOG.debug( "Project Remote repository ID: {}", ar.getId() ); } ProjectBuildingResult build = mavenProjectBuilder.build( artifact, request ); MavenProject depProject = build.getProject(); - LOG.debug("Dependency {}Collecting information from project metadata for {}", artifact.getArtifactId(), depProject.getArtifactId()); + LOG.debug( "Dependency {}Collecting information from project metadata for {}", artifact.getArtifactId(), + depProject.getArtifactId() ); return createSpdxPackage( depProject, useArtifactID ); } catch ( SpdxCollectionException e ) { - LOG.error("SPDX File Collection Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); + LOG.error( "SPDX File Collection Error creating SPDX package for dependency artifact ID {}:{}", + artifact.getArtifactId(), e.getMessage() ); } catch ( NoSuchAlgorithmException e ) { - LOG.error("Verification Code Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); + LOG.error( "Verification Code Error creating SPDX package for dependency artifact ID {}:{}", + artifact.getArtifactId(), e.getMessage() ); } catch ( ProjectBuildingException e ) { - LOG.error("Maven Project Build Error creating SPDX package for dependency artifact ID {}:{}", artifact.getArtifactId(), e.getMessage()); + LOG.error( "Maven Project Build Error creating SPDX package for dependency artifact ID {}:{}", + artifact.getArtifactId(), e.getMessage() ); } - LOG.warn("Error creating SPDX package for dependency artifact ID {}. A minimal SPDX package will be created.", artifact.getArtifactId()); + LOG.warn( "Error creating SPDX package for dependency artifact ID {}. A minimal SPDX package will be created.", + artifact.getArtifactId() ); // Create a minimal SPDX package from dependency // Name will be the artifact ID - LOG.debug("Dependency {}Using only artifact information to create dependent package", artifact.getArtifactId()); + LOG.debug( "Dependency {}Using only artifact information to create dependent package", + artifact.getArtifactId() ); return spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), artifact.getArtifactId(), new SpdxNoAssertionLicense(), "NOASSERTION", new SpdxNoAssertionLicense() ) @@ -456,7 +470,7 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd if ( externalRef == null ) { String externalRefDocId = SpdxConstantsCompatV2.EXTERNAL_DOC_REF_PRENUM + fixExternalRefId( fullArtifactId ); - LOG.debug("Creating external document ref {}", externalDocNamespace); + LOG.debug( "Creating external document ref {}", externalDocNamespace ); org.spdx.maven.Checksum mavenChecksum = AbstractFileCollector.generateSha1( spdxFile ); Checksum cksum = spdxDoc.createChecksum( ChecksumAlgorithm.valueOf( mavenChecksum.getAlgorithm() ), mavenChecksum.getValue() ); @@ -468,7 +482,7 @@ private SpdxElement createExternalSpdxPackageReference( SpdxDocument externalSpd "External document ref '"+externalRefDocId+"' created for artifact "+fullArtifactId ); spdxDoc.getAnnotations().add( docRefAddedAnnotation ); this.externalDocuments.put( externalDocNamespace, externalRef ); - LOG.debug("Created external document ref {}", externalRefDocId); + LOG.debug( "Created external document ref {}", externalRefDocId ); } SpdxPackage pkg = findMatchingDescribedPackage( externalSpdxDoc, artifactId ); return new ExternalSpdxElement( spdxDoc.getModelStore(), spdxDoc.getDocumentUri(), @@ -488,12 +502,12 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc Optional downloadLocation = source.getDownloadLocation(); Optional name = source.getName(); SpdxPackage dest = spdxDoc.createPackage( spdxDoc.getModelStore().getNextId( IdType.SpdxId ), - name.orElse("NONE"), source.getLicenseConcluded(), source.getCopyrightText(), + name.orElse( "NONE" ), source.getLicenseConcluded(), source.getCopyrightText(), source.getLicenseDeclared() ) .setFilesAnalyzed( false ) .setAnnotations( source.getAnnotations() ) .setChecksums( source.getChecksums() ) - .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) + .setDownloadLocation( downloadLocation.orElse( "NOASSERTION" ) ) .setExternalRefs( source.getExternalRefs() ) .build(); // We don't want to copy any of the properties which have other elements since it diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java index 3ddf6d8..0facfd8 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2DocumentBuilder.java @@ -194,7 +194,7 @@ private void fillCreatorInfo( SpdxProjectInformation projectInformation ) throws } else { - LOG.warn("Invalid creator string ( {} ), {} will be skipped.", verify, parameterCreator); + LOG.warn( "Invalid creator string ( {} ), {} will be skipped.", verify, parameterCreator ); } } SpdxCreatorInformation spdxCreator = spdxDoc.createCreationInfo( creators, format.format( new Date() ) ); @@ -218,7 +218,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } else { - LOG.warn("Invalid download location in POM file: {}", projectInformation.getDownloadUrl()); + LOG.warn( "Invalid download location in POM file: {}", projectInformation.getDownloadUrl() ); } if ( downloadUrl == null ) { @@ -295,7 +295,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } catch( InvalidSPDXAnalysisException ex ) { - LOG.warn("Invalid URL in project POM file: {}", projectInformation.getHomePage()); + LOG.warn( "Invalid URL in project POM file: {}", projectInformation.getHomePage() ); } } @@ -349,7 +349,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation } catch ( IllegalArgumentException | NullPointerException e1 ) { - LOG.error("Invalid checksum algorithm {}", checksum.getAlgorithm()); + LOG.error( "Invalid checksum algorithm {}", checksum.getAlgorithm() ); } } } @@ -462,7 +462,7 @@ public ExternalRef convertExternalRef( ExternalReference externalReference ) thr } catch ( Exception ex ) { - throw new MojoExecutionException("External reference category " + externalReference.getCategory() + " is not recognized as a valid, standard category." ); + throw new MojoExecutionException( "External reference category " + externalReference.getCategory() + " is not recognized as a valid, standard category." ); } ReferenceType refType; try diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java index 91e909d..017a02e 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2FileCollector.java @@ -128,7 +128,7 @@ public void collectFiles(List fileSets, String baseDir, */ private @Nullable SpdxDefaultFileInformation findDefaultFileInformation(String filePath, Map pathSpecificInformation ) { - LOG.debug("Checking for file path {}", filePath); + LOG.debug( "Checking for file path {}", filePath ); SpdxDefaultFileInformation retval = pathSpecificInformation.get( filePath ); if ( retval != null ) { @@ -149,7 +149,8 @@ public void collectFiles(List fileSets, String baseDir, } while ( retval == null && parentPathIndex > 0 ); if ( retval != null ) { - LOG.debug("Found directory containing file path for path specific information. File path: {}", parentPath); + LOG.debug( "Found directory containing file path for path specific information. File path: {}", + parentPath ); } return retval; } @@ -321,7 +322,7 @@ private SpdxFile convertToSpdxFile( File file, String outputFileName, } catch ( InvalidSPDXAnalysisException e ) { - LOG.error("Invalid license expressions found in source file {}", file.getName(), e); + LOG.error( "Invalid license expressions found in source file {}", file.getName(), e ); } if ( licenseComment == null ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java index a80f3f8..06a5cf0 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV2LicenseManager.java @@ -127,9 +127,10 @@ public void addExtractedLicense( NonStandardLicense license ) throws LicenseMana if ( this.urlStringToSpdxLicenseId.containsKey( url ) ) { String oldLicenseId = urlStringToSpdxLicenseId.get( url ); - LOG.warn("Duplicate URL for SPDX extracted license. Replacing {} with {} for {}", oldLicenseId, license.getLicenseId(), url); + LOG.warn( "Duplicate URL for SPDX extracted license. Replacing {} with {} for {}", + oldLicenseId, license.getLicenseId(), url ); } - LOG.debug("Adding URL mapping for non-standard license {}", spdxLicense.getLicenseId()); + LOG.debug( "Adding URL mapping for non-standard license {}", spdxLicense.getLicenseId() ); this.urlStringToSpdxLicenseId.put( url, spdxLicense.getLicenseId() ); } } @@ -192,7 +193,7 @@ public AnyLicenseInfo mavenLicenseToSpdxLicense( License mavenLicense ) throws L throw new LicenseManagerException( "Can not map maven license " + mavenLicense.getName() + " No URL exists to provide a mapping" ); } - String licenseId = this.urlStringToSpdxLicenseId.get( mavenLicense.getUrl().replaceAll("https:", "http:") ); + String licenseId = this.urlStringToSpdxLicenseId.get( mavenLicense.getUrl().replaceAll( "https:", "http:" ) ); if ( licenseId == null ) { throw new LicenseManagerException( @@ -270,7 +271,8 @@ private License spdxStdLicenseToMavenLicense( SpdxListedLicense spdxLicense ) th if ( spdxLicense.getSeeAlso().size() > 1 ) { //noinspection LoggingSimilarMessage - LOG.warn("SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", spdxLicense.getLicenseId()); + LOG.warn( "SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", + spdxLicense.getLicenseId() ); } return retval; } catch ( InvalidSPDXAnalysisException e ) @@ -305,7 +307,8 @@ private License spdxNonStdLicenseToMavenLicense( ExtractedLicenseInfo spdxLicens if ( spdxLicense.getSeeAlso().size() > 1 ) { //noinspection LoggingSimilarMessage - LOG.warn("SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", spdxLicense.getLicenseId()); + LOG.warn( "SPDX license {} contains multiple URLs. Only the first URL will be preserved in the Maven license created.", + spdxLicense.getLicenseId() ); } return retval; } diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java index cc8be18..788f641 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DependencyBuilder.java @@ -102,7 +102,8 @@ protected void addMavenDependency( CoreModelObject parentPackage, DependencyNode { if ( !(parentPackage instanceof SpdxPackage) ) { - LOG.error("Invalid type for parent package. Expected 'SpdxPackage', found {}", parentPackage.getClass().getName()); + LOG.error( "Invalid type for parent package. Expected 'SpdxPackage', found {}", + parentPackage.getClass().getName() ); return; } Artifact dependency = dependencyNode.getArtifact(); @@ -456,9 +457,9 @@ private Element copyPackageInfoFromV2File( String path, String artifactId ) thro Optional name = source.getName(); SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) - .setName(name.orElse("NONE")) + .setName(name.orElse( "NONE" )) .setCopyrightText( source.getCopyrightText() != null ? source.getCopyrightText() : "NOASSERTION" ) - .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) + .setDownloadLocation(downloadLocation.orElse( "NOASSERTION" )) .build(); Optional pvc = source.getPackageVerificationCode(); @@ -739,7 +740,7 @@ private SpdxDocument spdxDocumentFromFile( String path ) throws FileNotFoundExce try { modelStore.close(); } catch (Exception e) { - LOG.error("Error closing SPDX model store", e); + LOG.error( "Error closing SPDX model store", e ); } } } @@ -757,10 +758,10 @@ private SpdxPackage copyPackageInfoFromExternalDoc( SpdxDocument externalSpdxDoc Optional downloadLocation = source.getDownloadLocation(); Optional name = source.getName(); SpdxPackage dest = spdxDoc.createSpdxPackage( spdxDoc.getIdPrefix() + spdxDoc.getModelStore().getNextId( IdType.SpdxId ) ) - .setName(name.orElse("NONE")) + .setName( name.orElse( "NONE" ) ) .setCopyrightText( source.getCopyrightText().orElse( "NOASSERTION" ) ) .addAllVerifiedUsing( source.getVerifiedUsings() ) - .setDownloadLocation(downloadLocation.orElse("NOASSERTION")) + .setDownloadLocation( downloadLocation.orElse( "NOASSERTION" ) ) .addAllExternalIdentifier( source.getExternalIdentifiers() ) .addAllExternalRef( source.getExternalRefs() ) .addAllOriginatedBy( source.getOriginatedBys() ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java index 47f471e..41e038d 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxV3DocumentBuilder.java @@ -446,7 +446,8 @@ private void addExternalRefs( ExternalReference[] externalRefs, SoftwareArtifact } catch ( Exception ex ) { - throw new MojoExecutionException("External reference category " + externalRef.getCategory() + " is not recognized as a valid, standard category." ); + throw new MojoExecutionException( "External reference category " + externalRef.getCategory() + + " is not recognized as a valid, standard category." ); } ReferenceType refType; try