diff --git a/src/main/java/org/spdx/maven/Annotation.java b/src/main/java/org/spdx/maven/Annotation.java
index 6ed1564..0f6281e 100644
--- a/src/main/java/org/spdx/maven/Annotation.java
+++ b/src/main/java/org/spdx/maven/Annotation.java
@@ -15,11 +15,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;
@@ -28,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 );
@@ -125,38 +119,8 @@ 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(
- "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
new file mode 100644
index 0000000..17dde3c
--- /dev/null
+++ b/src/main/java/org/spdx/maven/Checksum.java
@@ -0,0 +1,82 @@
+/**
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Source Auditor Inc.
+ */
+package org.spdx.maven;
+
+import java.util.Objects;
+
+/**
+ * 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
+ */
+ @SuppressWarnings("unused")
+ 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 afda541..400a1b2 100644
--- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java
+++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java
@@ -37,37 +37,28 @@
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.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;
import org.spdx.maven.utils.SpdxDefaultFileInformation;
-import org.spdx.maven.utils.SpdxDependencyInformation;
-import org.spdx.maven.utils.SpdxDocumentBuilder;
-import org.spdx.maven.utils.SpdxFileCollector;
+import org.spdx.maven.utils.AbstractDependencyBuilder;
+import org.spdx.maven.utils.AbstractDocumentBuilder;
+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;
+import org.spdx.maven.utils.SpdxV3DependencyBuilder;
+import org.spdx.maven.utils.SpdxV3DocumentBuilder;
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.
@@ -95,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,
@@ -112,6 +104,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;
@@ -509,14 +506,13 @@ public void execute() throws MojoExecutionException
getLog().info( "Creating SPDX File " + spdxFile.getPath() );
- SpdxDocumentBuilder builder = initSpdxDocumentBuilder( outputFormatEnum );
- SpdxDocument spdxDoc = builder.getSpdxDoc();
+ AbstractDocumentBuilder builder = initSpdxDocumentBuilder( outputFormatEnum );
// fill project information
try
{
SpdxProjectInformation projectInformation = getSpdxProjectInfoFromParameters( builder );
- projectInformation.logInfo( spdxDoc );
+ projectInformation.logInfo();
builder.fillSpdxDocumentInformation( projectInformation );
}
catch ( InvalidSPDXAnalysisException e2 )
@@ -525,8 +521,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,9 +540,7 @@ public void execute() throws MojoExecutionException
// add dependencies information
try
{
- SpdxDependencyInformation dependencyInformation = getSpdxDependencyInformation( builder );
-
- builder.addDependencyInformation( dependencyInformation );
+ buildSpdxDependencyInformation( builder, outputFormatEnum );
}
catch ( LicenseMapperException e1 )
{
@@ -568,8 +562,8 @@ public void execute() throws MojoExecutionException
projectHelper.attachArtifact( mavenProject, artifactType, spdxFile );
// check errors
- List spdxErrors = builder.getSpdxDoc().verify();
- if ( spdxErrors != null && spdxErrors.size() > 0 )
+ List spdxErrors = builder.verify();
+ if ( spdxErrors != null && !spdxErrors.isEmpty() )
{
getLog().warn( "The following errors were found in the SPDX file:\n " + String.join( "\n ", spdxErrors ) );
}
@@ -599,11 +593,12 @@ 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;
}
- private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEnum )
+ private AbstractDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEnum )
throws MojoExecutionException
{
if ( onlyUseLocalLicenses )
@@ -614,7 +609,7 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn
defaultLicenseInformationInFile = defaultFileConcludedLicense;
}
- SpdxDocumentBuilder builder;
+ AbstractDocumentBuilder builder;
try
{
if ( spdxDocumentNamespace.startsWith( "http://spdx.org/spdxpackages/" )) {
@@ -622,8 +617,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 ( SpdxMajorVersion.VERSION_3.equals( outputFormatEnum.getSpecVersion() ) ) {
+ builder = new SpdxV3DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri,
+ outputFormatEnum );
+ }
+ else
+ {
+ builder = new SpdxV2DocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri,
+ outputFormatEnum );
+ }
+
}
catch ( SpdxBuilderException e )
{
@@ -653,18 +656,28 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn
}
/**
- * 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
+ * @throws LicenseMapperException on errors related to mapping Maven licenses to SPDX licenses
+ * @throws InvalidSPDXAnalysisException on SPDX parsing errors
*/
- private SpdxDependencyInformation getSpdxDependencyInformation( SpdxDocumentBuilder builder )
+ private void buildSpdxDependencyInformation( AbstractDocumentBuilder builder, OutputFormat outputFormatEnum )
throws LicenseMapperException, InvalidSPDXAnalysisException, DependencyGraphBuilderException
{
- SpdxDependencyInformation retval = new SpdxDependencyInformation( builder.getLicenseManager(), builder.getSpdxDoc(),
- createExternalRefs, generatePurls, useArtifactID,
- includeTransitiveDependencies );
+ AbstractDependencyBuilder dependencyBuilder;
+ if ( builder instanceof SpdxV3DocumentBuilder )
+ {
+ dependencyBuilder = new SpdxV3DependencyBuilder( (SpdxV3DocumentBuilder)builder, createExternalRefs,
+ generatePurls, useArtifactID,
+ includeTransitiveDependencies );
+ }
+ else
+ {
+ dependencyBuilder = new SpdxV2DependencyBuilder( (SpdxV2DocumentBuilder)builder,
+ createExternalRefs, generatePurls, useArtifactID,
+ includeTransitiveDependencies );
+ }
if ( session != null )
{
@@ -672,10 +685,8 @@ private SpdxDependencyInformation getSpdxDependencyInformation( SpdxDocumentBuil
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 )
@@ -694,29 +705,17 @@ 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,
- SpdxDocument spdxDoc ) throws MojoExecutionException
- {
+ private HashMap getPathSpecificInfoFromParameters( SpdxDefaultFileInformation projectDefault ) {
HashMap retval = new HashMap<>();
if ( this.pathsWithSpecificSpdxInfo != null )
{
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 );
- }
+ SpdxDefaultFileInformation value;
+ value = spdxInfo.getDefaultFileInformation( projectDefault );
if ( retval.containsKey( spdxInfo.getPath() ) )
{
getLog().warn( "Multiple file path specific SPDX data for " + spdxInfo.getPath() );
@@ -730,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 )
{
@@ -758,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 )
{
@@ -787,46 +786,16 @@ 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( SpdxDocument spdxDoc ) throws MojoExecutionException
- {
+ private SpdxDefaultFileInformation getDefaultFileInfoFromParameters() {
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;
@@ -845,63 +814,41 @@ private SpdxDefaultFileInformation getDefaultFileInfoFromParameters( SpdxDocumen
* " is prepended
*
* @param builder SPDX document builder
- * @return
- * @throws MojoExecutionException
+ * @return SPDX project level information
*/
- private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBuilder builder ) throws MojoExecutionException, InvalidSPDXAnalysisException
+ private SpdxProjectInformation getSpdxProjectInfoFromParameters( AbstractDocumentBuilder builder ) throws InvalidSPDXAnalysisException
{
- SpdxDocument spdxDoc = builder.getSpdxDoc();
SpdxProjectInformation retval = new SpdxProjectInformation();
if ( this.documentComment != null )
{
retval.setDocumentComment( this.documentComment );
}
- AnyLicenseInfo declaredLicense = null;
+ String declaredLicense;
if ( this.licenseDeclared == null )
{
List mavenLicenses = mavenProject.getLicenses();
try
{
- declaredLicense = builder.getLicenseManager().mavenLicenseListToSpdxLicense( mavenLicenses );
+ declaredLicense = builder.mavenLicenseListToSpdxLicenseExpression( mavenLicenses );
}
catch ( LicenseManagerException e )
{
getLog().warn( "Unable to map maven licenses to a declared license. Using NOASSERTION" );
- declaredLicense = new SpdxNoAssertionLicense();
+ declaredLicense = "NOASSERTION";
}
}
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;
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 );
@@ -909,7 +856,7 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBui
{
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 );
@@ -958,8 +905,8 @@ private SpdxProjectInformation getSpdxProjectInfoFromParameters( SpdxDocumentBui
try
{
getLog().debug( "Generating checksum for file "+packageFile.getAbsolutePath() );
- Set algorithms = getChecksumAlgorithms();
- checksums = SpdxFileCollector.generateChecksum( packageFile, algorithms, spdxDoc );
+ Set algorithms = getChecksumAlgorithms();
+ checksums = AbstractFileCollector.generateChecksum( packageFile, algorithms );
}
catch ( SpdxCollectionException | InvalidSPDXAnalysisException e )
{
@@ -989,16 +936,16 @@ 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;
}
/**
* 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()
{
@@ -1043,28 +990,17 @@ 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 );
- }
- }
+ 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 e32d412..37e778b 100644
--- a/src/main/java/org/spdx/maven/ExternalReference.java
+++ b/src/main/java/org/spdx/maven/ExternalReference.java
@@ -15,23 +15,14 @@
*/
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.
*
* @author Gary O'Neall
- * @see ExternalRef
- * @see ReferenceType
- * @see ReferenceCategory
+ *
*/
+@SuppressWarnings("unused")
public class ExternalReference
{
private String category;
@@ -42,37 +33,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/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 490ff4b..d4c2c57 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,18 +25,23 @@
*/
public enum OutputFormat
{
- RDF_XML("RDF/XML", "spdx.rdf.xml", ".rdf.xml"),
- JSON("JSON", "spdx.json", ".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)
+ 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)
@@ -45,7 +51,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 +69,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);
}
@@ -70,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..153b7c3 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)
+ 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/PathSpecificSpdxInfo.java b/src/main/java/org/spdx/maven/PathSpecificSpdxInfo.java
index f8956ad..1035d61 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;
/**
@@ -30,6 +24,7 @@
*
* @author Gary O'Neall
*/
+@SuppressWarnings("unused")
public class PathSpecificSpdxInfo
{
/**
@@ -88,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;
@@ -107,13 +102,10 @@ 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,
- SpdxDocument spdxDoc ) throws InvalidSPDXAnalysisException
+ public SpdxDefaultFileInformation getDefaultFileInformation( SpdxDefaultFileInformation defaults )
{
SpdxDefaultFileInformation retval = new SpdxDefaultFileInformation();
if ( this.fileComment != null )
@@ -126,12 +118,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 +158,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/SnippetInfo.java b/src/main/java/org/spdx/maven/SnippetInfo.java
index 7d9be16..60c3a31 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.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.maven.utils.SpdxBuilderException;
import org.slf4j.Logger;
@@ -65,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 );
}
}
@@ -98,18 +90,9 @@ public String getComment()
return this.comment;
}
- public AnyLicenseInfo getLicenseConcluded( SpdxDocument spdxDoc ) throws InvalidLicenseStringException
- {
- return LicenseInfoFactory.parseSPDXLicenseString( this.concludedLicense, spdxDoc.getModelStore(),
- spdxDoc.getDocumentUri(), spdxDoc.getCopyManager() );
- }
-
- public Collection getLicenseInfoInSnippet( SpdxDocument spdxDoc ) throws InvalidLicenseStringException
+ public String getLicenseConcluded()
{
- List retval = new ArrayList<>();
- retval.add( LicenseInfoFactory.parseSPDXLicenseString( 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/AbstractDependencyBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java
new file mode 100644
index 0000000..3ea9153
--- /dev/null
+++ b/src/main/java/org/spdx/maven/utils/AbstractDependencyBuilder.java
@@ -0,0 +1,195 @@
+/**
+ * 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 java.util.Objects;
+
+import javax.annotation.Nullable;
+
+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 @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() ))
+ {
+ File retval = getFileWithDifferentType( file, of.getFileType() );
+ if ( 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;
+ return new File( filePath );
+ }
+
+ 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: {}, file path: {}, Scope: {}", dependency.getArtifactId(), filePath, scope );
+ }
+ }
+
+ /**
+ * Make an external document reference ID valid by replacing any invalid characters with dashes
+ *
+ * @param externalRefId ID for external reference
+ * @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/AbstractDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java
new file mode 100644
index 0000000..107bb21
--- /dev/null
+++ b/src/main/java/org/spdx/maven/utils/AbstractDocumentBuilder.java
@@ -0,0 +1,144 @@
+/**
+ * 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.text.DateFormat;
+import java.text.SimpleDateFormat;
+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.library.model.v2.SpdxConstantsCompatV2;
+import org.spdx.maven.NonStandardLicense;
+import org.spdx.maven.OutputFormat;
+import org.spdx.storage.ISerializableModelStore;
+
+/**
+ * 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 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 ISerializableModelStore modelStore;
+ protected ModelCopyManager copyManager;
+ protected DateFormat format = new SimpleDateFormat( SpdxConstantsCompatV2.SPDX_DATE_FORMAT );
+
+
+ /**
+ * @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() );
+ }
+
+ }
+
+ /**
+ * @param projectInformation Information about project extracted from Maven metadata and parameters
+ * @throws SpdxBuilderException on errors adding document level information
+ */
+ public abstract void fillSpdxDocumentInformation( SpdxProjectInformation projectInformation ) throws SpdxBuilderException;
+
+ /**
+ * 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 checksumAlgorithms algorithms to use to generate checksums
+ * @throws SpdxBuilderException on errors collecting files
+ */
+ public abstract void collectSpdxFileInformation( List sources, String baseDir,
+ SpdxDefaultFileInformation defaultFileInformation,
+ HashMap pathSpecificInformation,
+ Set checksumAlgorithms ) throws SpdxBuilderException;
+
+ /**
+ * Saves the SPDX document to the file
+ * @throws SpdxBuilderException On any error saving the file
+ *
+ */
+ public abstract void saveSpdxDocumentToFile() throws SpdxBuilderException;
+
+ /**
+ * @param nonStandardLicenses non standard licenses to add
+ */
+ public abstract void addNonStandardLicenses( NonStandardLicense[] nonStandardLicenses ) throws SpdxBuilderException;
+
+ /**
+ * @return package representing the Mave project
+ */
+ public abstract CoreModelObject getProjectPackage();
+
+ /**
+ * @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 ) throws LicenseManagerException;
+
+ /**
+ * Verifies the top level document
+ * @return list of any errors or warnings
+ */
+ public abstract List verify();
+
+}
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..f61234d
--- /dev/null
+++ b/src/main/java/org/spdx/maven/utils/AbstractFileCollector.java
@@ -0,0 +1,238 @@
+/**
+ * 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.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 );
+ for (Entry