From 5b7e4f9025ec3b6498dd788846eded2dae915783 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 26 Sep 2020 22:52:17 -0700 Subject: [PATCH 1/6] Bump version and update POM file for production Signed-off-by: Gary O'Neall --- pom.xml | 211 +++++++++++++++++--- src/main/java/org/spdx/library/Version.java | 2 +- 2 files changed, 187 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index f0b84f9bf..0322195c0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,19 +1,85 @@ - 4.0.0 + 4.0.0 - org.spdx - java-spdx-library - 0.0.3-SNAPSHOT - jar - - java-spdx-library - http://maven.apache.org - - - UTF-8 - + org.spdx + java-spdx-library + 0.0.4-SNAPSHOT + jar + java-spdx-library + http://maven.apache.org + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + goneall + Gary O'Neall + gary@sourceauditor.com + SPDX + http://spdx.org + + + + SPDX + http://spdx.org + + + https://github.com/spdx/Spdx-Java-Library + https://github.com/spdx/Spdx-Java-Library.git + https://github.com/spdx/Spdx-Java-Library.git + + + + bintray-spdx-spdx-tools + spdx-spdx-tools + https://api.bintray.com/maven/spdx/spdx-tools/java-spdx-library/;publish=1 + + + + UTF-8 + + + + doclint-java8-disable + + [1.8,) + + + -Xdoclint:none + + + + gpg-signing + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + ${gpg.keyname} + ${gpg.keyname} + + + + + + + + junit @@ -94,20 +160,115 @@ - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + ${project.build.sourceEncoding} + true + true + true + + - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 + org.apache.maven.plugins + maven-javadoc-plugin + 2.9 + + true + 8 + ${java.home}/bin/javadoc + -Xdoclint:none + + + + attach-javadocs + + ${javadoc.opts} + + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + verify + + jar-no-fork + + + + + + org.spdx + spdx-maven-plugin + 0.5.3 + + + build-spdx + prepare-package + + createSPDX + + + - 1.8 - 1.8 - ${project.build.sourceEncoding} - true - true - true - - - + http://spdx.org/documents/java-spdx-library-{$version} + + Copyright (c) 2020 Source Auditor Inc. + + Gary O'Neall + + Apache-2.0 + Apache-2.0 + 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. + Apache-2.0 + Apache-2.0 + + Person: Gary O'Neall + + Organization: Linux Foundation + + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.1 + + + + + Github + https://github.com/spdx/Spdx-Java-Library/issues + + Java library which implements the Java object model for SPDX and provides useful helper functions. + + Github Actions + https://github.com/spdx/Spdx-Java-Library/actions + diff --git a/src/main/java/org/spdx/library/Version.java b/src/main/java/org/spdx/library/Version.java index c5bacbd66..530a75302 100644 --- a/src/main/java/org/spdx/library/Version.java +++ b/src/main/java/org/spdx/library/Version.java @@ -46,7 +46,7 @@ public class Version { TWO_POINT_ONE_VERSION, TWO_POINT_TWO_VERSION }))); - public static final String CURRENT_IMPLEMENTATION_VERSION = "2.2.0"; + public static final String CURRENT_IMPLEMENTATION_VERSION = "0.3"; public static String verifySpdxVersion(String spdxVersion) { if (!spdxVersion.startsWith("SPDX-")) { From 75c78fbcfc5fbee3a6af555b2346acd35fedc4e5 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 26 Sep 2020 22:53:37 -0700 Subject: [PATCH 2/6] Add support for equivalent string and NOASSERTION/NONE and normalized linefeeds for strings Signed-off-by: Gary O'Neall --- .../org/spdx/library/model/ModelObject.java | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/spdx/library/model/ModelObject.java b/src/main/java/org/spdx/library/model/ModelObject.java index f679e1c6b..f96d6d152 100644 --- a/src/main/java/org/spdx/library/model/ModelObject.java +++ b/src/main/java/org/spdx/library/model/ModelObject.java @@ -749,7 +749,7 @@ public boolean equivalent(ModelObject compare, boolean ignoreRelatedElements) th return false; } - } else if (!Objects.equals(myValue, compareValue)) { // Present, not a list, and not a TypedValue + } else if (!OptionalObjectsEquivalent(myValue, compareValue)) { // Present, not a list, and not a TypedValue return false; } comparePropertyValueNames.remove(propertyName); @@ -774,6 +774,53 @@ public boolean equivalent(ModelObject compare, boolean ignoreRelatedElements) th return true; } + /** + * Compares 2 simple optional objects considering NONE and NOASSERTION values which are equivalent to their strings + * @param valueA + * @param valueB + * @return + */ + private boolean OptionalObjectsEquivalent(Optional valueA, Optional valueB) { + if (Objects.equals(valueA, valueB)) { + return true; + } + if (!valueA.isPresent()) { + return false; + } + if (!valueB.isPresent()) { + return false; + } + if (valueA.get() instanceof IndividualUriValue) { + if (SpdxConstants.URI_VALUE_NONE.equals(((IndividualUriValue)valueA.get()).getIndividualURI()) && SpdxConstants.NONE_VALUE.equals(valueB.get())) { + return true; + } + if (SpdxConstants.URI_VALUE_NOASSERTION.equals(((IndividualUriValue)valueA.get()).getIndividualURI()) && SpdxConstants.NOASSERTION_VALUE.equals(valueB.get())) { + return true; + } + } + if (valueB.get() instanceof IndividualUriValue) { + if (SpdxConstants.URI_VALUE_NONE.equals(((IndividualUriValue)valueB.get()).getIndividualURI()) && SpdxConstants.NONE_VALUE.equals(valueA.get())) { + return true; + } + if (SpdxConstants.URI_VALUE_NOASSERTION.equals(((IndividualUriValue)valueB.get()).getIndividualURI()) && SpdxConstants.NOASSERTION_VALUE.equals(valueA.get())) { + return true; + } + } + if (valueA.get() instanceof String && valueB.get() instanceof String) { + return normalizeString((String)valueA.get()).equals(normalizeString((String)valueB.get())); + } + return false; + } + + /** + * Normalize a string for dos and linux linefeeds + * @param s + * @return linux style only linefeeds + */ + private Object normalizeString(String s) { + return s.replaceAll("\r\n", "\n").trim(); + } + /** * @param l1 * @param l2 From af0c8faa31384c33ec8cfcbaf3ab5d3d1621a763 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 26 Sep 2020 22:54:49 -0700 Subject: [PATCH 3/6] Set the default filesAnalyzed to allow packages to match when default is not set Signed-off-by: Gary O'Neall --- src/main/java/org/spdx/library/model/SpdxPackage.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/spdx/library/model/SpdxPackage.java b/src/main/java/org/spdx/library/model/SpdxPackage.java index 6aab161fb..cc3b97a45 100644 --- a/src/main/java/org/spdx/library/model/SpdxPackage.java +++ b/src/main/java/org/spdx/library/model/SpdxPackage.java @@ -52,6 +52,9 @@ public class SpdxPackage extends SpdxItem implements Comparable { */ public SpdxPackage() throws InvalidSPDXAnalysisException { super(); + if (!getBooleanPropertyValue(SpdxConstants.PROP_PACKAGE_FILES_ANALYZED).isPresent()) { + this.setFilesAnalyzed(true); // Set default value + } } /** @@ -66,6 +69,9 @@ public SpdxPackage(IModelStore modelStore, String documentUri, String id, @Nullable ModelCopyManager copyManager, boolean create) throws InvalidSPDXAnalysisException { super(modelStore, documentUri, id, copyManager, create); + if (!getBooleanPropertyValue(SpdxConstants.PROP_PACKAGE_FILES_ANALYZED).isPresent()) { + this.setFilesAnalyzed(true); // Set default value + } } /** @@ -74,6 +80,9 @@ public SpdxPackage(IModelStore modelStore, String documentUri, String id, */ public SpdxPackage(String id) throws InvalidSPDXAnalysisException { super(id); + if (!getBooleanPropertyValue(SpdxConstants.PROP_PACKAGE_FILES_ANALYZED).isPresent()) { + this.setFilesAnalyzed(true); // Set default value + } } protected SpdxPackage(SpdxPackageBuilder spdxPackageBuilder) throws InvalidSPDXAnalysisException { From 7f5dec7fceedf92ce7661eedb2408cbd063f154b Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 26 Sep 2020 22:57:20 -0700 Subject: [PATCH 4/6] Fix SPDX comparer errors when comparing multiple documents Signed-off-by: Gary O'Neall --- .../java/org/spdx/utility/compare/SpdxComparer.java | 10 +++++----- .../org/spdx/utility/compare/SpdxItemDifference.java | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/spdx/utility/compare/SpdxComparer.java b/src/main/java/org/spdx/utility/compare/SpdxComparer.java index 551bc8b24..3abdf5df0 100644 --- a/src/main/java/org/spdx/utility/compare/SpdxComparer.java +++ b/src/main/java/org/spdx/utility/compare/SpdxComparer.java @@ -498,7 +498,7 @@ protected List collectAllPackages(SpdxDocument spdxDocument) throws * @throws InvalidSPDXAnalysisException */ @SuppressWarnings("unchecked") - protected List collectAllFiles(SpdxDocument spdxDocument) throws InvalidSPDXAnalysisException { + public List collectAllFiles(SpdxDocument spdxDocument) throws InvalidSPDXAnalysisException { return (List)SpdxModelFactory.getElements(spdxDocument.getModelStore(), spdxDocument.getDocumentUri(), null, SpdxFile.class).collect(Collectors.toList()); } @@ -858,9 +858,9 @@ private void compareDocumentFields() throws SpdxCompareException { private void compareDocumentContents() throws SpdxCompareException { documentContentsEquals = true; try { - for (int i = 0; i < spdxDocs.size(); i++) { + for (int i = 0; i < spdxDocs.size()-1; i++) { Collection itemsA = spdxDocs.get(i).getDocumentDescribes(); - for (int j = i; j < spdxDocs.size(); j++) { + for (int j = i+1; j < spdxDocs.size(); j++) { Collection itemsB = spdxDocs.get(j).getDocumentDescribes(); if (!collectionsEquivalent(itemsA, itemsB)) { this.documentContentsEquals = false; @@ -952,7 +952,7 @@ private void compareExtractedLicenseInfos() throws InvalidSPDXAnalysisException, continue; // no need to compare to ourself; } Map idMap = new HashMap<>(); - List alDifferences = new ArrayList<>();; + List alDifferences = new ArrayList<>(); Collection extractedLicensesB = spdxDocs.get(j).getExtractedLicenseInfos(); List uniqueLicenses = new ArrayList<>(); compareLicenses(extractedLicensesA, extractedLicensesB, @@ -1062,7 +1062,7 @@ private boolean nonTextLicenseFieldsEqual( * @param stringsB * @return */ - static boolean stringCollectionsEqual(Collection stringsA, Collection stringsB) { + public static boolean stringCollectionsEqual(Collection stringsA, Collection stringsB) { if (stringsA == null) { return stringsB == null; } else { diff --git a/src/main/java/org/spdx/utility/compare/SpdxItemDifference.java b/src/main/java/org/spdx/utility/compare/SpdxItemDifference.java index f0ad5caa4..3e0b12a9c 100644 --- a/src/main/java/org/spdx/utility/compare/SpdxItemDifference.java +++ b/src/main/java/org/spdx/utility/compare/SpdxItemDifference.java @@ -63,7 +63,11 @@ public SpdxItemDifference(SpdxItem itemA, SpdxItem itemB, List uniqueAnnotationsA, List uniqueAnnotationsB ) throws SpdxCompareException, InvalidSPDXAnalysisException { - this.name = itemA.getName().get(); + if (itemA.getName().isPresent()) { + this.name = itemA.getName().get(); + } else { + this.name = ""; + } if (itemA.getComment().isPresent()) { this.commentA = itemA.getComment().get(); } else { From 5b3472f14bf5a8c789ddf256138ba2dd76b76454 Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Sat, 26 Sep 2020 22:57:46 -0700 Subject: [PATCH 5/6] Add verification code generation utility function Signed-off-by: Gary O'Neall --- .../org/spdx/rdfparser/DOAPProject.java | 213 +++ .../rdfparser/GenerateVerificationCode.java | 144 ++ .../rdfparser/IFileChecksumGenerator.java | 29 + .../InvalidSPDXAnalysisException.java | 35 + .../rdfparser/JavaSha1ChecksumGenerator.java | 68 + .../org/spdx/rdfparser/LicenseHTMLFile.java | 151 ++ .../spdx/rdfparser/LicenseRDFAGenerator.java | 233 +++ .../org/spdx/rdfparser/LicenseSheet.java | 202 +++ .../spdx/rdfparser/LicenseTOCHTMLFile.java | 108 ++ .../rdfparser/NoStandardLicenseRdfModel.java | 47 + .../org/spdx/rdfparser/PrettyPrinter.java | 191 +++ .../org/spdx/rdfparser/SPDXChecksum.java | 168 ++ .../rdfparser/SPDXConjunctiveLicenseSet.java | 106 ++ .../rdfparser/SPDXCreatorInformation.java | 282 ++++ .../rdfparser/SPDXDisjunctiveLicenseSet.java | 106 ++ .../org/spdx/rdfparser/SPDXDocument.java | 1356 +++++++++++++++++ .../spdx/rdfparser/SPDXDocumentFactory.java | 92 ++ .../org/spdx/rdfparser/SPDXFile.java | 483 ++++++ .../org/spdx/rdfparser/SPDXLicense.java | 198 +++ .../org/spdx/rdfparser/SPDXLicenseInfo.java | 117 ++ .../rdfparser/SPDXLicenseInfoFactory.java | 541 +++++++ .../org/spdx/rdfparser/SPDXLicenseSet.java | 117 ++ .../rdfparser/SPDXNonStandardLicense.java | 102 ++ .../org/spdx/rdfparser/SPDXNoneLicense.java | 83 + .../org/spdx/rdfparser/SPDXPackageInfo.java | 310 ++++ .../org/spdx/rdfparser/SPDXReview.java | 250 +++ .../spdx/rdfparser/SPDXStandardLicense.java | 262 ++++ .../rdfparser/SpdxNoAssertionLicense.java | 87 ++ .../SpdxPackageVerificationCode.java | 168 ++ .../org/spdx/rdfparser/SpdxRdfConstants.java | 154 ++ .../rdfparser/SpdxVerificationHelper.java | 175 +++ .../rdfparser/VerificationCodeGenerator.java | 164 ++ .../VerificationCodeGeneratorTest.java | 61 + .../org/spdx/rdfparser/package-info.java | 5 + .../spdx/spdxspreadsheet/AbstractSheet.java | 174 +++ .../spdxspreadsheet/AbstractSpreadsheet.java | 129 ++ .../InvalidLicenseStringException.java | 36 + .../NonStandardLicensesSheet.java | 167 ++ .../spdx/spdxspreadsheet/OriginsSheet.java | 303 ++++ .../spdxspreadsheet/PackageInfoSheet.java | 58 + .../PackageInfoSheetV09d2.java | 337 ++++ .../PackageInfoSheetV09d3.java | 384 +++++ .../spdxspreadsheet/PackageInfoSheetV9d1.java | 307 ++++ .../spdx/spdxspreadsheet/PerFileSheet.java | 273 ++++ .../spdxspreadsheet/RdfToSpreadsheet.java | 197 +++ .../spdx/spdxspreadsheet/ReviewersSheet.java | 178 +++ .../SPDXLicenseSpreadsheet.java | 131 ++ .../spdx/spdxspreadsheet/SPDXSpreadsheet.java | 214 +++ .../spdxspreadsheet/SpreadsheetException.java | 33 + .../spdxspreadsheet/SpreadsheetToRDF.java | 251 +++ .../IFileChecksumGenerator.java | 29 + .../JavaSha1ChecksumGenerator.java | 68 + .../VerificationCodeGenerator.java | 241 +++ .../verificationcode/package-info.java | 24 + .../VerificationCodeGeneratorTest.java | 121 ++ 55 files changed, 10463 insertions(+) create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/DOAPProject.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/GenerateVerificationCode.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/IFileChecksumGenerator.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/InvalidSPDXAnalysisException.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/JavaSha1ChecksumGenerator.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseHTMLFile.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseRDFAGenerator.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseTOCHTMLFile.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/NoStandardLicenseRdfModel.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/PrettyPrinter.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXChecksum.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXConjunctiveLicenseSet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXCreatorInformation.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDisjunctiveLicenseSet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocument.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocumentFactory.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXFile.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicense.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfo.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfoFactory.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseSet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNonStandardLicense.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNoneLicense.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXPackageInfo.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXReview.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXStandardLicense.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxNoAssertionLicense.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxPackageVerificationCode.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxRdfConstants.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxVerificationHelper.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGenerator.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGeneratorTest.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/rdfparser/package-info.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSpreadsheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/InvalidLicenseStringException.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/NonStandardLicensesSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/OriginsSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d2.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d3.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV9d1.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PerFileSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/RdfToSpreadsheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/ReviewersSheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXLicenseSpreadsheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXSpreadsheet.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetException.java create mode 100644 TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetToRDF.java create mode 100644 src/main/java/org/spdx/utility/verificationcode/IFileChecksumGenerator.java create mode 100644 src/main/java/org/spdx/utility/verificationcode/JavaSha1ChecksumGenerator.java create mode 100644 src/main/java/org/spdx/utility/verificationcode/VerificationCodeGenerator.java create mode 100644 src/main/java/org/spdx/utility/verificationcode/package-info.java create mode 100644 src/test/java/org/spdx/utility/verificationcode/VerificationCodeGeneratorTest.java diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/DOAPProject.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/DOAPProject.java new file mode 100644 index 000000000..8c1ec4f3b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/DOAPProject.java @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Contains a DOAP project + * Currently, only the home page and name properties are supported + * @author Gary O'Neall + * + */ +public class DOAPProject { + + static final String UNKNOWN_URI = "UNKNOWN"; + private String name = null; + private String homePage = null; + private Node projectNode = null; + private Resource projectResource = null; + private Model model = null; + private String uri = null; + + /** + * This method will create a DOAP Project object from a DOAP document + * which already exists. The DOAP project is read from the uri and + * the model is created from the existing data. + * @param model Jena model to populate + * @param projectUrl The URL of the DOAP project + * @return + * @throws InvalidSPDXAnalysisException + */ + static DOAPProject getExistingProject(Model model, String projectUrl) throws InvalidSPDXAnalysisException { + Resource projectResource = model.createResource(projectUrl); + model.read(projectUrl); + return new DOAPProject(model, projectResource.asNode()); + } + + public DOAPProject(Model model, Node node) throws InvalidSPDXAnalysisException { + this.model = model; + this.projectNode = node; + if (projectNode.isBlank()) { + this.projectResource = model.createResource(node.getBlankNodeId()); + } else if (projectNode.isURI()) { + this.projectResource = model.createResource(node.getURI()); + this.uri = node.getURI(); + } else { + throw(new InvalidSPDXAnalysisException("Can not create a DOAP project from a literal node")); + } + + // name + Node p = model.getProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_NAME).asNode(); + Triple m = Triple.createMatch(projectNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.name = t.getObject().toString(false); + } + // home page + p = model.getProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_HOMEPAGE).asNode(); + m = Triple.createMatch(projectNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.homePage = t.getObject().toString(false); + } + } + + /** + * @param projectName + * @param homePage + */ + public DOAPProject(String projectName, String homePage) { + this.name = projectName; + this.homePage = homePage; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + if (this.projectNode != null && this.model != null) { + Property p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_NAME); + model.removeAll(projectResource, p, null); + p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_NAME); + projectResource.addProperty(p, name); + } + } + + /** + * @return the homePage + */ + public String getHomePage() { + return homePage; + } + + /** + * @param homePage the homePage to set + */ + public void setHomePage(String homePage) { + this.homePage = homePage; + if (this.projectNode != null && this.model != null) { + Property p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_HOMEPAGE); + model.removeAll(projectResource, p, null); + if (homePage != null) { + p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_HOMEPAGE); + Resource homePageResource = model.createResource(homePage); + projectResource.addProperty(p, homePageResource); + } + } + } + + public String getProjectUri() { + if (projectNode == null) { + if (uri == null || uri.isEmpty()) { + return UNKNOWN_URI; + } else { + return uri; + } + } else { + if (projectNode.isURI()) { + return projectNode.getURI(); + } else { + return UNKNOWN_URI; + } + } + } + + public Resource createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.DOAP_NAMESPACE + SpdxRdfConstants.CLASS_DOAP_PROJECT); + Resource retval; + if (uri != null && !uri.isEmpty() && !uri.equals(UNKNOWN_URI)) { + retval = model.createResource(uri, type); + } else { + retval = model.createResource(type); + } + populateModel(model, retval); + return retval; + } + + /** + * @param model Jena model to populate + * @param projectResource Project resource to populate + */ + private void populateModel(Model model, Resource projectResource) { + this.model = model; + this.projectNode = projectResource.asNode(); + this.projectResource = projectResource; + + // Name + if (name != null) { + Property p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_NAME); + projectResource.addProperty(p, name); + } + + // HomePage + if (homePage != null) { + Property p = model.createProperty(SpdxRdfConstants.DOAP_NAMESPACE, SpdxRdfConstants.PROP_PROJECT_HOMEPAGE); + projectResource.addProperty(p, homePage); + } + } + + /** + * @return + */ + public ArrayList verify() { + return new ArrayList(); // anything to verify? + } + + /** + * @param uri + * @throws InvalidSPDXAnalysisException + */ + public void setUri(String uri) throws InvalidSPDXAnalysisException { + if (this.projectResource != null) { + if (!this.projectResource.hasURI(uri)) { + throw(new InvalidSPDXAnalysisException("Can not set a URI value for a resource which has already been created.")); + } + } + if (!uri.equals(UNKNOWN_URI) &&!SpdxVerificationHelper.isValidUri(uri)) { + throw(new InvalidSPDXAnalysisException("Invalid URI for DOAP Project "+this.name+": "+uri)); + } + this.uri = uri; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/GenerateVerificationCode.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/GenerateVerificationCode.java new file mode 100644 index 000000000..f48dfa600 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/GenerateVerificationCode.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.util.ArrayList; +import java.util.regex.Pattern; + +/** + * Generates a verification code for a specific directory + * @author Gary O'Neall + * + */ +public class GenerateVerificationCode { + + /** + * Print an SPDX Verification code for a directory of files + * args[0] is the source directory containing the files + * args[1] is an optional regular expression of skipped files. The expression is applied against a file path relative the the source directory supplied + * @param args + */ + public static void main(String[] args) { + if (args.length < 1 || args.length > 2) { + error("Incorrect number of arguments."); + System.exit(1); + } + File sourceDirectory = new File(args[0]); + if (!sourceDirectory.exists()) { + error("Source directory "+args[0]+" does not exist."); + System.exit(1); + } + if (!sourceDirectory.isDirectory()) { + error("File "+args[0]+" is not a directory."); + System.exit(1); + } + String skippedRegex = null; + File[] skippedFiles = new File[0]; + if (args.length > 1) { + skippedRegex = args[1]; + skippedFiles = collectSkippedFiles(skippedRegex, sourceDirectory); + } + try { + VerificationCodeGenerator vcg = new VerificationCodeGenerator(new JavaSha1ChecksumGenerator()); + SpdxPackageVerificationCode verificationCode = vcg.generatePackageVerificationCode(sourceDirectory, skippedFiles); + printVerificationCode(verificationCode); + System.exit(0); + } catch (Exception ex) { + error("Error creating verification code: "+ex.getMessage()); + } + } + + /** + * Collect files to be skipped + * @param skippedRegex Regular Expression for file paths to be skipped + * @param dir Directory to scan for collecting skipped files + * @return + */ + private static File[] collectSkippedFiles(String skippedRegex, File dir) { + Pattern skippedPattern = Pattern.compile(skippedRegex); + ArrayList skippedFiles = new ArrayList(); + collectSkippedFiles(skippedPattern, skippedFiles, dir.getPath(), dir); + File[] retval = new File[skippedFiles.size()]; + retval = skippedFiles.toArray(retval); + return retval; + } + + /** + * Internal method to recurse through the source directory collecting files to skip + * @param skippedPattern + * @param skippedFiles + * @param rootPath + * @param dir + * @return + */ + private static void collectSkippedFiles(Pattern skippedPattern, + ArrayList skippedFiles, String rootPath, File dir) { + if (dir.isFile()) { + String relativePath = dir.getPath().substring(rootPath.length()+1); + if (skippedPattern.matcher(relativePath).matches()) { + skippedFiles.add(dir); + } + } else if (dir.isDirectory()) { + File[] children = dir.listFiles(); + for (int i = 0; i < children.length; i++) { + if (children[i].isFile()) { + String relativePath = children[i].getPath().substring(rootPath.length()+1); + if (skippedPattern.matcher(relativePath).matches()) { + skippedFiles.add(children[i]); + } + } else if (children[i].isDirectory()) { + collectSkippedFiles(skippedPattern, skippedFiles, rootPath, children[i]); + } + } + } + } + + /** + * @param verificationCode + */ + private static void printVerificationCode( + SpdxPackageVerificationCode verificationCode) { + System.out.println("Verification code value: "+verificationCode.getValue()); + String[] excludedFiles = verificationCode.getExcludedFileNames(); + if (excludedFiles != null && excludedFiles.length > 0) { + System.out.println("Excluded files:"); + for (int i = 0; i < excludedFiles.length; i++) { + System.out.println("\t"+excludedFiles[i]); + } + } else { + System.out.println("No excluded files"); + } + } + + /** + * @param string + */ + private static void error(String string) { + System.out.println(string); + usage(); + } + + /** + * + */ + private static void usage() { + System.out.println("Usage: GenerateVerificationCode sourceDirectory"); + System.out.println("where sourceDirectory is the root of the archive file for which the verification code is generated"); + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/IFileChecksumGenerator.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/IFileChecksumGenerator.java new file mode 100644 index 000000000..495d66740 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/IFileChecksumGenerator.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.IOException; + +/** + * Interface for implementations of generators of file checksums + * @author Gary O'Neall + * + */ +public interface IFileChecksumGenerator { + public String getFileChecksum(File file) throws IOException; +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/InvalidSPDXAnalysisException.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/InvalidSPDXAnalysisException.java new file mode 100644 index 000000000..a641c9ef7 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/InvalidSPDXAnalysisException.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010 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.rdfparser; + +/** + * Exception for invalid SPDX Documents + * @author Gary O'Neall + * + */ +public class InvalidSPDXAnalysisException extends Exception { + /** + * + */ + private static final long serialVersionUID = -8042590523688807173L; + public InvalidSPDXAnalysisException(String msg) { + super(msg); + } + public InvalidSPDXAnalysisException(String msg, Throwable inner) { + super(msg, inner); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/JavaSha1ChecksumGenerator.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/JavaSha1ChecksumGenerator.java new file mode 100644 index 000000000..9c2c4a3b9 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/JavaSha1ChecksumGenerator.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Java sha1 checksum generator using MessageDigest + * @author Gary O'Neall + * + */ +public class JavaSha1ChecksumGenerator implements IFileChecksumGenerator { + static final String SHA1_ALGORITHM = "SHA-1"; + static final String PACKAGE_VERIFICATION_CHARSET = "UTF-8"; + private MessageDigest digest = null; + + public JavaSha1ChecksumGenerator() throws NoSuchAlgorithmException { + this.digest = MessageDigest.getInstance(SHA1_ALGORITHM); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.IFileChecksumGenerator#getFileChecksum(java.io.File) + */ + @Override + public String getFileChecksum(File file) throws IOException { + digest.reset(); + FileInputStream in = new FileInputStream(file); + try { + byte[] buffer = new byte[2048]; + int numBytes = in.read(buffer); + while (numBytes >= 0) { + digest.update(buffer, 0, numBytes); + numBytes = in.read(buffer); + } + byte[] digestBytes = digest.digest(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < digestBytes.length; i++) { + String hex = Integer.toHexString(0xff & digestBytes[i]); + if (hex.length() < 2) { + sb.append("0"); + } + sb.append(hex); + } + return sb.toString(); + } finally { + in.close(); + } + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseHTMLFile.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseHTMLFile.java new file mode 100644 index 000000000..1945326ad --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseHTMLFile.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringEscapeUtils; + +/** + * This class contains a formatted HTML file for a given license. Specific + * formatting information is contained in this file. + * @author Gary O'Neall + * + */ +public class LicenseHTMLFile { + static final boolean USE_SITE = false; // set to true to use the site name for the link of external web pages + static final String TITLE = "[TITLE]"; + static final String NAME = "[NAME]"; + static final String ID = "[LICENSEID]"; + static final String WEBURL = "[WEBURL]"; + static final String SITE = "[SITE]"; + static final String NOTES = "[NOTES]"; + static final String OTHERWEBPAGE = "[OTHERWEBPAGE]"; + static final String OTHER_WEB_PAGE_ROW = + "
  • "+SITE+"
  • \n"; + static final String LICENSE_TEXT = "[LICENSE_TEXT]"; + static final Pattern SITE_PATTERN = Pattern.compile("http://(.*)\\.(.*)(\\.org|\\.com|\\.net|\\.info)"); + + private String template; + + private SPDXStandardLicense license; + public LicenseHTMLFile(String template, SPDXStandardLicense license) { + this.template = template; + this.license = license; + } + public LicenseHTMLFile(String template) { + this.template = template; + this.license = null; + } + + /** + * @return the license + */ + public SPDXStandardLicense getLicense() { + return license; + } + + /** + * @param license the license to set + */ + public void setLicense(SPDXStandardLicense license) { + this.license = license; + } + + public void setTemplate(String template) { + this.template = template; + } + + public String getTemplate() { + return this.template; + } + + public void writeToFile(File htmlFile, String tableOfContentsReference) throws IOException { + FileOutputStream stream = null; + OutputStreamWriter writer = null; + if (!htmlFile.exists()) { + if (!htmlFile.createNewFile()) { + throw(new IOException("Can not create new file "+htmlFile.getName())); + } + } + try { + String htmlText = template.replace(ID, escapeHTML(license.getId())); + htmlText = htmlText.replace(LICENSE_TEXT, escapeHTML(license.getText())); + htmlText = htmlText.replace(NAME, escapeHTML(license.getName())); + String notes; + if (license.getNotes() != null && !license.getNotes().isEmpty()) { + notes = escapeHTML(license.getNotes()); + } else { + notes = "None"; + } + htmlText = htmlText.replace(NOTES, notes); + String otherWebPages; + if (license.getSourceUrl() != null && !license.getSourceUrl().isEmpty()) { + StringBuilder sb = new StringBuilder(); + String[] sourceUrls = license.getSourceUrl().split(" "); + for (int i = 0; i < sourceUrls.length; i++) { + String url = sourceUrls[i].trim(); + if (url.isEmpty()) { + continue; + } + String site = getSiteFromUrl(url); + String urlRow = OTHER_WEB_PAGE_ROW.replace(WEBURL, url); + urlRow = urlRow.replace(SITE, site); + sb.append(urlRow); + sb.append("\n"); + } + otherWebPages = sb.toString(); + } else { + otherWebPages = "None"; + } + htmlText = htmlText.replace(OTHERWEBPAGE, otherWebPages); + htmlText = htmlText.replace(TITLE, escapeHTML(license.getName())); + stream = new FileOutputStream(htmlFile); + writer = new OutputStreamWriter(stream, "UTF-8"); + writer.write(htmlText); + } catch (FileNotFoundException e) { + throw(e); + } finally { + if (writer != null) { + writer.close(); + } + if (stream != null) { + stream.close(); + } + } + } + @SuppressWarnings("unused") + private String getSiteFromUrl(String url) { + Matcher matcher = SITE_PATTERN.matcher(url); + if (matcher.find() && USE_SITE) { + int numGroups = matcher.groupCount(); + return matcher.group(numGroups-1); + } else { + return url; + } + } + private String escapeHTML(String text) { + String retval = StringEscapeUtils.escapeXml(text); + return retval.replace("\n", "
    \n"); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseRDFAGenerator.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseRDFAGenerator.java new file mode 100644 index 000000000..0b7bd7f30 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseRDFAGenerator.java @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.HashSet; +import java.util.Iterator; + +import org.spdx.spdxspreadsheet.SPDXLicenseSpreadsheet; +import org.spdx.spdxspreadsheet.SpreadsheetException; + +import com.google.common.collect.Sets; + +/** + * Converts a spreadsheet containing SPDX License information into RDFA + * HTML pages describing the licenses. + * @author Gary O'Neall + * + */ +public class LicenseRDFAGenerator { + static final Set INVALID_FILE_CHARS = Sets.newHashSet(); + + static { + + INVALID_FILE_CHARS.add('\\'); INVALID_FILE_CHARS.add('/'); INVALID_FILE_CHARS.add('*'); + INVALID_FILE_CHARS.add('<'); INVALID_FILE_CHARS.add('>'); INVALID_FILE_CHARS.add('['); + INVALID_FILE_CHARS.add(']'); INVALID_FILE_CHARS.add('='); // INVALID_FILE_CHARS.add('+'); + INVALID_FILE_CHARS.add(';'); INVALID_FILE_CHARS.add(':'); + INVALID_FILE_CHARS.add('\''); INVALID_FILE_CHARS.add('"'); INVALID_FILE_CHARS.add('|'); + INVALID_FILE_CHARS.add('\t'); INVALID_FILE_CHARS.add('?'); INVALID_FILE_CHARS.add('&'); + INVALID_FILE_CHARS.add('�'); + } + static int MIN_ARGS = 2; + static int MAX_ARGS = 2; + + static final String CSS_FILE_TEXT = "body { font-family: Tahoma, Verdana, sans-serif; }\n\n.license-text {\n"+ + "background-color: WhiteSmoke;\nborder: 1px dashed Black;\npadding: 1ex;\n}\n\nh2 {\n"+ + "border-bottom: 1px solid Gray;\n}\ndt {\nfont-weight: bold;\n}\n\nul {\n"+ + "padding-left: 1em;\n}\n\ntable {\nborder-collapse: collapse;\n}\n"+ + "td,th {\nmargin: 0;\nborder: 1px solid black;\n}\n"; + static final String CSS_FILE_NAME = "screen.css"; + static final String LICENSE_HTML_TEMPLATE_FILENAME = "resources/LicenseHTMLTemplate.txt"; + static final String TOC_HTML_TEMPLATE_FILENAME = "resources/TocHTMLTemplate.txt"; + /** + * @param args Arg 0 is the input spreadsheet, arg 1 is the directory for the output html files + */ + public static void main(String[] args) { + if (args == null || args.length < MIN_ARGS || args.length > MAX_ARGS) { + System.out.println("Invalid arguments"); + usage(); + return; + } + File ssFile = new File(args[0]); + if (!ssFile.exists()) { + System.out.println("Spreadsheet file "+ssFile.getName()+" does not exist"); + usage(); + return; + } + File dir = new File(args[1]); + if (!dir.exists()) { + System.out.println("Output directory "+dir.getName()+" does not exist"); + usage(); + return; + } + if (!dir.isDirectory()) { + System.out.println("Output directory "+dir.getName()+" is not a directory"); + usage(); + return; + } + File htmlTemplateFile = new File(LICENSE_HTML_TEMPLATE_FILENAME); + if (!htmlTemplateFile.exists()) { + System.out.println("Missing HTML template file "+htmlTemplateFile.getPath()+". Check installation"); + return; + } + if (!htmlTemplateFile.canRead()) { + System.out.println("Can not read HTML template file "+htmlTemplateFile.getPath()+". Make sure program is installed in a directory with read permissions."); + return; + } + String htmlTemplate = textFileToString(htmlTemplateFile); + if (htmlTemplate == null) { + System.out.println("Error: empty HTML template"); + return; + } + File tocTemplateFile = new File(TOC_HTML_TEMPLATE_FILENAME); + if (!tocTemplateFile.exists()) { + System.out.println("Missing Table of Contents template file "+tocTemplateFile.getPath()+". Check installation"); + return; + } + if (!tocTemplateFile.canRead()) { + System.out.println("Can not read Table of Contents template file "+tocTemplateFile.getPath()+". Make sure program is installed in a directory with read permissions."); + return; + } + String tocTemplate = textFileToString(tocTemplateFile); + if (tocTemplate == null) { + System.out.println("Error: empty Table of Contents template"); + return; + } + SPDXLicenseSpreadsheet ss = null; + try { + ss = new SPDXLicenseSpreadsheet(ssFile, false, true); + LicenseHTMLFile licHtml = new LicenseHTMLFile(htmlTemplate); + LicenseTOCHTMLFile tableOfContents = new LicenseTOCHTMLFile(tocTemplate); + Iterator iter = ss.getIterator(); + String tocFileName = "index.html"; + while (iter.hasNext()) { + SPDXStandardLicense license = iter.next(); + if (license.getId() != null && !license.getId().isEmpty()) { + System.out.println("Processing "+license.toString()); + licHtml.setLicense(license); + String licHtmlFileName = formLicenseHTMLFileName(license); + String licHTMLReference = "./"+licHtmlFileName; + String tocHTMLReference = "./"+tocFileName; + File licHtmlFile = new File(dir.getPath()+File.separator+licHtmlFileName); + licHtml.writeToFile(licHtmlFile, tocHTMLReference); + tableOfContents.addLicense(license, licHTMLReference); + } + } + File tocHtmlFile = new File(dir.getPath()+File.separator+tocFileName); + tableOfContents.writeToFile(tocHtmlFile); + writeCssFile(dir); + } catch (SpreadsheetException e) { + System.out.println("Invalid spreadsheet: "+e.getMessage()); + } catch (Exception e) { + System.out.println("Unhandled exception generating html:"); + e.printStackTrace(); + } finally { + if (ss != null) { + try { + ss.close(); + } catch (SpreadsheetException e) { + System.out.println("Error closing spreadsheet file: "+e.getMessage()); + } + } + } + } + /** + * @param htmlTemplateFile + * @return + */ + private static String textFileToString(File htmlTemplateFile) { + InputStreamReader reader = null; + BufferedReader in = null; + String retval = null; + try { + reader = new InputStreamReader(new FileInputStream(htmlTemplateFile), "UTF-8"); + in = new BufferedReader(reader); + StringBuilder sb = new StringBuilder(); + String line = in.readLine(); + while (line != null) { + sb.append(line); + sb.append('\n'); + line = in.readLine(); + } + retval = sb.toString(); + } catch (IOException e) { + System.out.println("IO Error copying HTML template files: "+e.getMessage()); + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + System.out.println("Warning - error closing HTML template file. Processing will continue. Error: "+e.getMessage()); + } + } + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + System.out.println("Warning - error closing HTML template file. Processing will continue. Error: "+e.getMessage()); + } + } + } + return retval; + } + private static void writeCssFile(File dir) throws IOException { + File cssFile = new File(dir.getPath()+ File.separator + CSS_FILE_NAME); + if (cssFile.exists()) { + return; // assume we don't need to create it + } + FileOutputStream stream = null; + OutputStreamWriter writer = null; + try { + stream = new FileOutputStream(cssFile); + writer = new OutputStreamWriter(stream); + writer.write(CSS_FILE_TEXT); + } finally { + if (writer != null) { + writer.close(); + } + if (stream != null) { + stream.close(); + } + } + + } + private static String formLicenseHTMLFileName(SPDXStandardLicense license) { + StringBuilder sb = new StringBuilder(); + String licId = license.getId(); + for (int i = 0; i < licId.length(); i++) { + if (INVALID_FILE_CHARS.contains(licId.charAt(i))) { + sb.append("_"); + } else { + sb.append(licId.charAt(i)); + } + } +// sb.append(".html"); + return sb.toString(); + } + private static void usage() { + System.out.println("Usage:"); + System.out.println("LicenseRDFAGenerator licenseSpreadsheet.xls outputDirectory"); + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseSheet.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseSheet.java new file mode 100644 index 000000000..61d19cd14 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseSheet.java @@ -0,0 +1,202 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.spdxspreadsheet.AbstractSheet; + +/** + * Spreadsheet holding SPDX Licenses + * @author Gary O'Neall + * + */ +public class LicenseSheet extends AbstractSheet { + + static final int NUM_COLS = 8; + static final int COL_NAME = 0; + static final int COL_ID = COL_NAME + 1; + static final int COL_SOURCE_URL = COL_ID + 1; + static final int COL_NOTES = COL_SOURCE_URL + 1; + static final int COL_OSI_APPROVED = COL_NOTES + 1; + static final int COL_STANDARD_LICENSE_HEADER = COL_OSI_APPROVED + 1; + static final int COL_TEXT = COL_STANDARD_LICENSE_HEADER + 1; + static final int COL_TEMPLATE = COL_TEXT + 1; + + static final boolean[] REQUIRED = new boolean[] {true, true, false, false, + false, false, true, false}; + static final String[] HEADER_TITLES = new String[] {"Full name of License", "License Identifier", "Source/url", "Notes", + "OSI Approved", "Standard License Header", "Text", "Template"}; + + public LicenseSheet(Workbook workbook, String sheetName) { + super(workbook, sheetName); + } + /** + * Create a blank worksheet NOTE: Replaces / deletes existing sheet by the same name + */ + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + Cell cell = row.createCell(i); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void add(SPDXStandardLicense license) { + Row row = addRow(); + Cell nameCell = row.createCell(COL_NAME); + nameCell.setCellValue(license.getName()); + Cell idCell = row.createCell(COL_ID); + idCell.setCellValue(license.getId()); + if (license.getSourceUrl() != null) { + Cell sourceUrlCell = row.createCell(COL_SOURCE_URL); + sourceUrlCell.setCellValue(license.getSourceUrl()); + } + if (license.getNotes() != null) { + Cell notesCell = row.createCell(COL_NOTES); + notesCell.setCellValue(license.getNotes()); + } + if (license.getStandardLicenseHeader() != null) { + Cell standardLicenseHeaderCell = row.createCell(COL_STANDARD_LICENSE_HEADER); + standardLicenseHeaderCell.setCellValue(license.getStandardLicenseHeader()); + } + Cell textCell = row.createCell(COL_TEXT); + textCell.setCellValue(license.getText()); + if (license.getTemplate() != null) { + Cell templateCell = row.createCell(COL_TEMPLATE); + templateCell.setCellValue(license.getTemplate()); + } + if (license.isOsiApproved()) { + Cell osiApprovedCell = row.createCell(COL_OSI_APPROVED); + osiApprovedCell.setCellValue("YES"); + } + } + + public SPDXStandardLicense getLicense(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + String id = null; + Cell idCell = row.getCell(COL_ID); + if (idCell != null) { + id = idCell.getStringCellValue(); + } + String name = null; + Cell nameCell = row.getCell(COL_NAME); + if (nameCell != null) { + name = nameCell.getStringCellValue(); + } + String notes = null; + Cell notesCell = row.getCell(COL_NOTES); + if (notesCell != null) { + notes = notesCell.getStringCellValue(); + } + String sourceURL = null; + Cell sourceURLCell = row.getCell(COL_SOURCE_URL); + if (sourceURLCell != null) { + sourceURL = sourceURLCell.getStringCellValue(); + } + String stdLicHeader = null; + Cell stdLicHeaderCell = row.getCell(COL_STANDARD_LICENSE_HEADER); + if (stdLicHeaderCell != null) { + stdLicHeader = stdLicHeaderCell.getStringCellValue(); + } + String template = null; + Cell templateCell = row.getCell(COL_TEMPLATE); + if (templateCell != null) { + template = templateCell.getStringCellValue(); + } + String text = null; + Cell textCell = row.getCell(COL_TEXT); + if (textCell != null) { + text = textCell.getStringCellValue(); + } + boolean osiApproved = false; + Cell osiApprovedCell = row.getCell(COL_OSI_APPROVED); + if (osiApprovedCell != null) { + String osiApprovedStr = osiApprovedCell.getStringCellValue(); + if (osiApprovedStr != null && osiApprovedStr.toUpperCase().trim().startsWith("Y")) { + osiApproved = true; + } + } + return new SPDXStandardLicense(name, id, text, sourceURL, notes, stdLicHeader, template, osiApproved); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Licenses does not exist"; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Licenses worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX License work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseTOCHTMLFile.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseTOCHTMLFile.java new file mode 100644 index 000000000..a504caec6 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/LicenseTOCHTMLFile.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; + +import org.apache.commons.lang.StringEscapeUtils; + +/** + * This class holds a formatted HTML file for a license table of contents + * @author Source Auditor + * + */ +public class LicenseTOCHTMLFile { + + static final String TABLE_ROW = "[TABLEROW]"; + static final String REFERENCE = "[REFERENCE]"; + static final String REFNUMBER = "[REFERENCE_NUMBER]"; + static final String LICENSEID = "[LICENSEID]"; + static final String LICENSE_NAME = "[LICENSE_NAME]"; + static final String OSI_APPROVED = "[OSI_APPROVED]"; + static final String ROW_TEMPLATE = " \n "+LICENSE_NAME+"\n"+ + " \n"+ + " "+LICENSEID+"\n"+ + " "+OSI_APPROVED+"\n"+ + " License Text\n"+ + " \n"; + ArrayList tableRows = new ArrayList(); + + private int currentRefNumber = 1; + + String template; + + public LicenseTOCHTMLFile(String template) { + this.template = template; + } + + public void addLicense(SPDXStandardLicense license, String licHTMLReference) { + String newRow = ROW_TEMPLATE.replace(REFERENCE, licHTMLReference); + currentRefNumber++; + newRow = newRow.replace(REFNUMBER, String.valueOf(this.currentRefNumber)); + newRow = newRow.replace(LICENSE_NAME, escapeHTML(license.getName())); + newRow = newRow.replace(LICENSEID, escapeHTML(license.getId())); + if (license.isOsiApproved()) { + newRow = newRow.replace(OSI_APPROVED, "Y"); + } else { + newRow = newRow.replace(OSI_APPROVED, ""); + } + tableRows.add(newRow); + } + + private String escapeHTML(String s) { + return StringEscapeUtils.escapeHtml(s); + } + + public void writeToFile(File htmlFile) throws IOException { + FileOutputStream stream = null; + OutputStreamWriter writer = null; + if (!htmlFile.exists()) { + if (!htmlFile.createNewFile()) { + throw(new IOException("Can not create new file "+htmlFile.getName())); + } + } + try { + stream = new FileOutputStream(htmlFile); + writer = new OutputStreamWriter(stream, "UTF-8"); + int rowLocation = template.indexOf(TABLE_ROW); + String firstPart = template.substring(0, rowLocation); + String lastPart = template.substring(rowLocation + TABLE_ROW.length()); + writer.write(firstPart); + for (int i = 0; i < this.tableRows.size(); i++) { + writer.write(this.tableRows.get(i)); + } + writer.write(lastPart); + } catch (FileNotFoundException e) { + throw(e); + } finally { + if (writer != null) { + writer.close(); + } + if (stream != null) { + stream.close(); + } + } + } + + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/NoStandardLicenseRdfModel.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/NoStandardLicenseRdfModel.java new file mode 100644 index 000000000..739463eed --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/NoStandardLicenseRdfModel.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +/** + * @author Gary O'Neall + * + */ +public class NoStandardLicenseRdfModel extends InvalidSPDXAnalysisException { + + /** + * + */ + private static final long serialVersionUID = 4045777176566797553L; + + /** + * @param msg + */ + public NoStandardLicenseRdfModel(String msg) { + super(msg); + // TODO Auto-generated constructor stub + } + + /** + * @param msg + * @param inner + */ + public NoStandardLicenseRdfModel(String msg, Throwable inner) { + super(msg, inner); + // TODO Auto-generated constructor stub + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/PrettyPrinter.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/PrettyPrinter.java new file mode 100644 index 000000000..4798bf493 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/PrettyPrinter.java @@ -0,0 +1,191 @@ +/** + * Copyright (c) 2010 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.rdfparser;import java.util.ArrayList;import org.spdx.rdfparser.SPDXDocument.SPDXPackage;/** + * Simple pretty printer for SPDX RDF XML files. Writes output to System.out. + * Usage: PrettyPrinter SPDXRdfXMLFile > textFile + * where SPDXRdfXMLFile is a valid SPDX RDF XML file + * + * @author Gary O'Neall + * @version 0.1 + */ +public class PrettyPrinter { + static final int MIN_ARGS = 1; + static final int MAX_ARGS = 1; + /** + * Pretty Printer for an SPDX Document + * @param args Argument 0 is a the file path name of the SPDX RDF/XML file + */ + public static void main(String[] args) { + if (args.length < MIN_ARGS) { + System.err.println("Usage:\n PrettyPrinter file\nwhere file is the file path to a valid SPDX RDF XML file"); + return; + } + if (args.length > MAX_ARGS) { + System.out.printf("Warning: Extra arguments will be ignored"); + } + SPDXDocument doc = null; + try { + doc = SPDXDocumentFactory.creatSpdxDocument(args[0]); + } catch(Exception ex) { + System.out.print("Error creating SPDX Document: "+ex.getMessage()); + return; + } + try { ArrayList verify = doc.verify(); if (verify.size() > 0) { System.out.println("This SPDX Document is not valid due to:"); for (int i = 0; i < verify.size(); i++) { System.out.print("\t" + verify.get(i)); } } + prettyPrintDoc(doc); + } catch (InvalidSPDXAnalysisException e) { + System.out.print("Error pretty printing SPDX Document: "+e.getMessage()); + return; + } catch (Exception e) { System.out.print("Unexpected error displaying SPDX Document: "+e.getMessage()); } + } + + /** + * @param doc + * @throws InvalidSPDXAnalysisException + */ + private static void prettyPrintDoc(SPDXDocument doc) throws InvalidSPDXAnalysisException { + if (doc == null) { + System.out.println("Warning: No document to print"); + return; + } + if (doc.getSpdxDocUri() != null) { + System.out.printf("SPDX Document for %1s\n",doc.getSpdxDocUri()); + } String spdxVersion = ""; + if (doc.getSpdxVersion() != null && doc.getCreatorInfo().getCreated() != null) { spdxVersion = doc.getSpdxVersion(); + System.out.printf("Version: %1s\tCreated: %2s\n", spdxVersion, doc.getCreatorInfo().getCreated()); + } if (!spdxVersion.equals(SPDXDocument.POINT_EIGHT_SPDX_VERSION) && !spdxVersion.equals(SPDXDocument.POINT_NINE_SPDX_VERSION)) { SPDXStandardLicense dataLicense = doc.getDataLicense(); if (dataLicense != null) { System.out.printf("Data License: %1s\n", dataLicense.getName()); } } + if (doc.getCreatorInfo().getCreators() != null && doc.getCreatorInfo().getCreators().length > 0) { + System.out.println("Created by:"); + String[] creators = doc.getCreatorInfo().getCreators(); + for (int i = 0; i < creators.length; i++) { + System.out.printf("\t%1s\n", creators[i]); + } + } if (doc.getCreatorInfo().getCreated() != null && !doc.getCreatorInfo().getCreated().isEmpty()) { System.out.printf("\t%1s\n", doc.getCreatorInfo().getCreated()); } + if (doc.getCreatorInfo().getComment() != null && !doc.getCreatorInfo().getComment().isEmpty()) { + System.out.println("Creator comment: "+doc.getCreatorInfo().getComment()); + } + if (doc.getReviewers() != null && doc.getReviewers().length > 0) { + System.out.println("Reviewed by:"); + SPDXReview[] reviewedBy = doc.getReviewers(); + for (int i = 0; i < reviewedBy.length; i++) { + if (reviewedBy[i].getComment() != null && !reviewedBy[i].getComment().isEmpty()) { + System.out.printf("\t%1s\t%2s\tComment:%3s\n",reviewedBy[i].getReviewer(), + reviewedBy[i].getReviewDate(), reviewedBy[i].getComment()); + } else { + System.out.printf("\t%1s\t%2s\n",reviewedBy[i].getReviewer(), + reviewedBy[i].getReviewDate()); + } + } + } + prettyPrintPackage(doc.getSpdxPackage()); + if (doc.getExtractedLicenseInfos() != null && doc.getExtractedLicenseInfos().length > 0) { + SPDXNonStandardLicense[] nonStandardLic = doc.getExtractedLicenseInfos(); + System.out.println("Non-Standard Licenses:"); + for (int i = 0; i < nonStandardLic.length; i++) { + prettyPrintLicense(nonStandardLic[i]); + } + } + } + + /** + * @param license + */ + private static void prettyPrintLicense(SPDXNonStandardLicense license) { + // id + if (license.getId() != null && !license.getId().isEmpty()) { + System.out.printf("\tLicense ID: %1s", license.getId()); + } + if (license.getText() != null && !license.getText().isEmpty()) { + System.out.printf("\tText: %1s", license.getText()); + } + System.out.println(); + } + + /** + * @param spdxPackage + * @throws InvalidSPDXAnalysisException + */ + private static void prettyPrintPackage(SPDXPackage pkg) throws InvalidSPDXAnalysisException { + // Declared name + if (pkg.getDeclaredName() != null && !pkg.getDeclaredName().isEmpty()) { + System.out.printf("Package Name: %1s\n", pkg.getDeclaredName()); + } + // Short description + if (pkg.getShortDescription() != null && !pkg.getShortDescription().isEmpty()) { + System.out.println(pkg.getShortDescription()); + } + // Source info + if (pkg.getSourceInfo() != null && !pkg.getSourceInfo().isEmpty()) { + System.out.printf("Additional Information: %1s\n", pkg.getSourceInfo()); + } + // File name + if (pkg.getFileName() != null && !pkg.getFileName().isEmpty()) { + System.out.printf("File name: %1s\n", pkg.getFileName()); + } // Supplier if (pkg.getSupplier() != null && !pkg.getSupplier().isEmpty()) { System.out.printf("Supplier: %1s\n", pkg.getSupplier()); } // Originator if (pkg.getOriginator() != null && !pkg.getOriginator().isEmpty()) { System.out.printf("Originator: %1s\n", pkg.getOriginator()); } + // sha1 + if (pkg.getSha1() != null && !pkg.getSha1().isEmpty()) { + System.out.printf("SHA1: %1s\n",pkg.getSha1()); + } + // package verification code + if (pkg.getVerificationCode() != null && pkg.getVerificationCode().getValue() != null && !pkg.getVerificationCode().getValue().isEmpty()) { + System.out.printf("Verification: %1s\n", pkg.getVerificationCode().getValue()); + } + // Description + if (pkg.getDescription() != null && !pkg.getDescription().isEmpty()) { + System.out.printf("Description: %1s\n", pkg.getDescription()); + } + // Declared copyright + if (pkg.getDeclaredCopyright() != null && ! pkg.getDeclaredCopyright().isEmpty()) { + System.out.printf("Declared Copyright: %1s\n", pkg.getDeclaredCopyright()); + } + // Declared licenses if (pkg.getDeclaredLicense() != null) { System.out.println("License declared: "+pkg.getDeclaredLicense()); } // concluded license if (pkg.getConcludedLicenses() != null) { System.out.println("License concluded: "+pkg.getConcludedLicenses()); } // file licenses + if (pkg.getLicenseInfoFromFiles() != null && pkg.getLicenseInfoFromFiles().length > 0) { + SPDXLicenseInfo[] licenses = pkg.getLicenseInfoFromFiles(); + System.out.println("Licenses from files:"); + for (int i = 0; i < licenses.length; i++) { + System.out.printf("\t%1s\n", licenses[i].toString()); + } + } if (pkg.getLicenseComment() != null && !pkg.getLicenseComment().isEmpty()) { System.out.println("License comments: "+pkg.getLicenseComment()); } + // Files + if (pkg.getFiles() != null && pkg.getFiles().length > 0) { + for (int i = 0; i < pkg.getFiles().length; i++) { + prettyPrintFile(pkg.getFiles()[i]); + } + } + } + + /** + * @param file + */ + private static void prettyPrintFile(SPDXFile file) { + // name + if (file.getName() != null && !file.getName().isEmpty()) { + System.out.printf("File Name: %1s\n", file.getName()); + } + // type + if (file.getType() != null && !file.getType().isEmpty()) { + System.out.printf("\tFile Type: %1s\n", file.getType()); + } + // sha1 + if (file.getSha1() != null && !file.getSha1().isEmpty()) { + System.out.printf("\tSHA1: %1s\n", file.getSha1()); + } + // concluded license + if (file.getConcludedLicenses() != null) { + System.out.println("\tConcluded license: "+file.getConcludedLicenses().toString()); + } // License info in file if (file.getSeenLicenses() != null && file.getSeenLicenses().length > 0) { System.out.print("\tLicense infos from file: "); System.out.print(file.getSeenLicenses()[0].toString()); for (int i = 1; i < file.getSeenLicenses().length; i++) { System.out.print(", "+file.getSeenLicenses()[i].toString()); } System.out.println(); } // license comments if (file.getLicenseComments() != null && !file.getLicenseComments().isEmpty()) { System.out.println("\tLicense comments: "+file.getLicenseComments()); } // file copyright if (file.getCopyright() != null && !file.getCopyright().isEmpty()) { System.out.println("\tFile copyright: "+file.getCopyright()); } // artifact of if (file.getArtifactOf() != null && file.getArtifactOf().length > 0) { for (int i = 0; i < file.getArtifactOf().length; i++) { prettyPrintProject(file.getArtifactOf()[i]); } } + } /** * @param doapProject */ private static void prettyPrintProject(DOAPProject doapProject) { // project name if (doapProject.getName() != null && !doapProject.getName().isEmpty()) { System.out.println("\t\tArtifact of Project: "+doapProject.getName()); } // project homepage if (doapProject.getHomePage() != null && !doapProject.getHomePage().isEmpty()) { System.out.println("\t\tArtifact of home page: "+doapProject.getHomePage()); } // DOAP file url if (doapProject.getProjectUri() != null && !doapProject.getProjectUri().isEmpty()) { System.out.println("\t\tArtifact of DOAP URI: "+doapProject.getProjectUri()); } } +} \ No newline at end of file diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXChecksum.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXChecksum.java new file mode 100644 index 000000000..c8bb5e181 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXChecksum.java @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * SPDX Checksum class for packages and files + * @author Gary O'Neall + * + */ +public class SPDXChecksum { + + // Supported algorithms + + public static final String ALGORITHM_SHA1 = "SHA1"; + private String algorithm; + private String value; + private Model model; + private Node checksumNode; + private Resource checksumResource; + + public SPDXChecksum(String algorithm, String value) { + this.algorithm = algorithm; + this.value = value; + } + + public SPDXChecksum(Model spdxModel, Node checksumNode) throws InvalidSPDXAnalysisException { + this.model = spdxModel; + this.checksumNode = checksumNode; + if (checksumNode.isBlank()) { + checksumResource = model.createResource(checksumNode.getBlankNodeId()); + } else if (checksumNode.isURI()) { + checksumResource = model.createResource(checksumNode.getURI()); + } else { + throw(new InvalidSPDXAnalysisException("Checksum node can not be a literal")); + } + // Algorithm + Node p = spdxModel.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_ALGORITHM).asNode(); + Triple m = Triple.createMatch(checksumNode, p, null); + ExtendedIterator tripleIter = spdxModel.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.algorithm = t.getObject().toString(false); + } + + // value + p = spdxModel.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_VALUE).asNode(); + m = Triple.createMatch(checksumNode, p, null); + tripleIter = spdxModel.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.value = t.getObject().toString(false); + } + } + + /** + * @return the algorithm + */ + public String getAlgorithm() { + return algorithm; + } + + /** + * @param algorithm the algorithm to set + */ + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + if (this.model != null && this.checksumNode != null) { + // delete any previous algorithm + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_ALGORITHM); + model.removeAll(checksumResource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_ALGORITHM); + checksumResource.addProperty(p, algorithm); + } + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @param value the value to set + */ + public void setValue(String value) { + this.value = value; + if (this.model != null && this.checksumNode != null) { + // delete any previous value + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_VALUE); + model.removeAll(checksumResource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_VALUE); + checksumResource.addProperty(p, value); + } + } + + /** + * Creates a resource from this SPDX Checksum + * @param model + * @return + */ + public Resource createResource(Model model) { + this.model = model; + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + + SpdxRdfConstants.CLASS_SPDX_CHECKSUM); + Resource r = model.createResource(type); + if (algorithm != null) { + Property algProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_CHECKSUM_ALGORITHM); + r.addProperty(algProperty, this.algorithm); + } + if (this.value != null) { + Property valueProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CHECKSUM_VALUE); + r.addProperty(valueProperty, this.value); + } + this.checksumNode = r.asNode(); + this.checksumResource = r; + return r; + } + + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String algorithm = this.getAlgorithm(); + if (algorithm == null || algorithm.isEmpty()) { + retval.add("Missing required algorithm"); + } else { + if (!algorithm.equals(ALGORITHM_SHA1)) { + retval.add("Unsupported checksum algorithm: "+algorithm); + } + } + String value = this.getValue(); + if (value == null || value.isEmpty()) { + retval.add("Missing required checksum value"); + } else { + String verify = SpdxVerificationHelper.verifyChecksumString(value); + if (verify != null) { + retval.add(verify); + } + } + return retval; + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXConjunctiveLicenseSet.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXConjunctiveLicenseSet.java new file mode 100644 index 000000000..4982ab842 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXConjunctiveLicenseSet.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.Iterator; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * A set of licenses where all of the licenses apply + * @author Gary O'Neall + * + */ +public class SPDXConjunctiveLicenseSet extends SPDXLicenseSet { + + /** + * @param model + * @param node + * @throws InvalidSPDXAnalysisException + */ + public SPDXConjunctiveLicenseSet(Model model, Node node) throws InvalidSPDXAnalysisException { + super(model, node); + } + + /** + * @param conjunctiveLicenses + */ + public SPDXConjunctiveLicenseSet(SPDXLicenseInfo[] conjunctiveLicenses) { + super(conjunctiveLicenses); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + SpdxRdfConstants.CLASS_SPDX_CONJUNCTIVE_LICENSE_SET); + return super._createResource(model, type); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("("); + boolean moreThanOne = false; + Iterator iter = this.licenseInfos.iterator(); + while (iter.hasNext()) { + if (moreThanOne) { + sb.append(" AND "); + } + moreThanOne = true; + sb.append(iter.next().toString()); + } + sb.append(")"); + return sb.toString(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXConjunctiveLicenseSet)) { + // covers o == null, as null is not an instance of anything + return false; + } + SPDXConjunctiveLicenseSet comp = (SPDXConjunctiveLicenseSet)o; + SPDXLicenseInfo[] compInfos = comp.getSPDXLicenseInfos(); + if (compInfos.length != this.licenseInfos.size()) { + return false; + } + Iterator iter = this.licenseInfos.iterator(); + while (iter.hasNext()) { + SPDXLicenseInfo li = iter.next(); + boolean found = false; + for (int i = 0; i < compInfos.length; i++) { + if (li.equals(compInfos[i])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXCreatorInformation.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXCreatorInformation.java new file mode 100644 index 000000000..b12e0bf34 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXCreatorInformation.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Creator class for SPDX documents + * @author Gary O'Neall + * + */ +public class SPDXCreatorInformation { + + private String[] creators = null; + private String comment = null; + private String createdDate = null; + private Node creatorNode = null; + private Model model = null; + private Resource creatorResource = null; + + /** + * @return the name + */ + public String[] getCreators() { + return creators; + } + + /** + * @param name the name to set + */ + public void setCreators(String[] creators) { + this.creators = creators; + if (this.creatorNode != null) { + // delete any previous comments + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATOR); + model.removeAll(creatorResource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATOR); + for (int i = 0; i < creators.length; i++) { + creatorResource.addProperty(p, creators[i]); + } + } + } + + /** + * @return the comment + */ + public String getComment() { + return comment; + } + + /** + * @param comment the comment to set + */ + public void setComment(String comment) { + this.comment = comment; + if (this.creatorNode != null) { + // delete any previous comments + Property p = model.getProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + model.removeAll(creatorResource, p, null); + if (comment != null) { + // add the property + p = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + creatorResource.addProperty(p, comment); + } + } + } + + public SPDXCreatorInformation(String[] creators, String createdDate, String comment) { + this.creators = creators; + this.createdDate = createdDate; + this.comment = comment; + } + + public SPDXCreatorInformation(Model spdxModel, Node creatorNode) throws InvalidSPDXAnalysisException { + this.model = spdxModel; + this.creatorNode = creatorNode; + if (creatorNode.isBlank()) { + creatorResource = model.createResource(creatorNode.getBlankNodeId()); + } else if (creatorNode.isURI()) { + creatorResource = model.createResource(creatorNode.getURI()); + } else { + throw(new InvalidSPDXAnalysisException("Creator node can not be a literal")); + } + // creators + Node p = spdxModel.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATOR).asNode(); + Triple m = Triple.createMatch(creatorNode, p, null); + ExtendedIterator tripleIter = spdxModel.getGraph().find(m); + ArrayList alCreators = new ArrayList(); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alCreators.add(t.getObject().toString(false)); + } + this.creators = alCreators.toArray(new String[alCreators.size()]); + // comment + p = spdxModel.getProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT).asNode(); + m = Triple.createMatch(creatorNode, p, null); + tripleIter = spdxModel.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.comment = t.getObject().toString(false); + } + // created + p = spdxModel.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATED).asNode(); + m = Triple.createMatch(creatorNode, p, null); + tripleIter = spdxModel.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.createdDate = t.getObject().toString(false); + } + } + + public Resource createResource(Model model) { + this.model = model; + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + + SpdxRdfConstants.CLASS_SPDX_CREATION_INFO); + Resource r = model.createResource(type); + if (creators != null && creators.length > 0) { + Property nameProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_CREATION_CREATOR); + for (int i = 0; i < creators.length; i++) { + r.addProperty(nameProperty, this.creators[i]); + } + } + if (this.comment != null) { + Property commentProperty = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + r.addProperty(commentProperty, this.comment); + } + // creation date + if (this.createdDate != null) { + Property createdDateProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATED); + r.addProperty(createdDateProperty, this.createdDate); + } + this.creatorNode = r.asNode(); + this.creatorResource = r; + return r; + } + + public String getCreated() { + return this.createdDate; + } + + public void setCreated(String createdDate) { + this.createdDate = createdDate; + if (this.creatorNode != null) { + // delete any previous comments + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATED); + model.removeAll(creatorResource, p, null); + if (comment != null) { + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_CREATION_CREATED); + creatorResource.addProperty(p, this.createdDate); + } + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXCreatorInformation)) { + return false; + } + SPDXCreatorInformation compCreator = (SPDXCreatorInformation)o; + if (compCreator.getCreated() == null) { + if (this.getCreated() != null) { + return false; + } + } else if (this.createdDate == null) { + return false; + } + else if (!compCreator.getCreated().equals(this.createdDate)) { + } + if (compCreator.getComment() == null) { + if (this.getComment() != null) { + return false; + } + } else if (this.getComment() == null) { + return false; + } + else if (!compCreator.getComment().equals(this.comment)) { + return false; + } + String[] compNames = compCreator.getCreators(); + if (compNames == null) { + if (this.creators != null) { + return false; + } + } else if (this.creators == null) { + return false; + } else { + if (compNames.length != this.creators.length) { + return false; + } + for (int i = 0; i < compNames.length; i++) { + boolean found = false; + for (int j = 0; j < this.creators.length; j++) { + if (compNames[i].equals(this.creators[j])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + } + return true; + + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (this.creators != null && this.creators.length > 0) { + sb.append(creators[0]); + for (int i = 0; i < creators.length; i++) { + sb.append(", "); + sb.append(creators[i]); + } + } + if (createdDate != null && !createdDate.isEmpty()) { + sb.append("; Created on "); + sb.append(createdDate); + } + if (comment != null && !comment.isEmpty()) { + sb.append("; Comment: "); + sb.append(comment); + } + return sb.toString(); + } + + /** + * @return + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String[] creators = this.getCreators(); + if (creators == null || creators.length == 0) { + retval.add("Missing required creators"); + } else { + for (int i = 0;i < creators.length; i++) { + String verify = SpdxVerificationHelper.verifyCreator(creators[i]); + if (verify != null) { + retval.add(verify); + } + } + } + String creationDate = this.getCreated(); + if (creationDate == null || creationDate.isEmpty()) { + retval.add("Missing required created date"); + } else { + String verify = SpdxVerificationHelper.verifyDate(creationDate); + if (verify != null) { + retval.add(verify); + } + } + @SuppressWarnings("unused") + String createdComments = this.getComment(); + // anything to verify for comments? + return retval; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDisjunctiveLicenseSet.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDisjunctiveLicenseSet.java new file mode 100644 index 000000000..d5229382b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDisjunctiveLicenseSet.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.Iterator; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * A set of licenses where there is a choice of one of the licenses in the set + * @author Gary O'Neall + * + */ +public class SPDXDisjunctiveLicenseSet extends SPDXLicenseSet { + + /** + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + public SPDXDisjunctiveLicenseSet(Model model, Node licenseInfoNode) throws InvalidSPDXAnalysisException { + super(model, licenseInfoNode); + } + + /** + * @param disjunctiveLicenses + */ + public SPDXDisjunctiveLicenseSet(SPDXLicenseInfo[] disjunctiveLicenses) { + super(disjunctiveLicenses); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + SpdxRdfConstants.CLASS_SPDX_DISJUNCTIVE_LICENSE_SET); + return super._createResource(model, type); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("("); + boolean moreThanOne = false; + Iterator iter = this.licenseInfos.iterator(); + while (iter.hasNext()) { + if (moreThanOne) { + sb.append(" OR "); + } + moreThanOne = true; + sb.append(iter.next().toString()); + } + sb.append(")"); + return sb.toString(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXDisjunctiveLicenseSet)) { + // covers o == null, as null is not an instance of anything + return false; + } + SPDXDisjunctiveLicenseSet comp = (SPDXDisjunctiveLicenseSet)o; + SPDXLicenseInfo[] compInfos = comp.getSPDXLicenseInfos(); + if (compInfos.length != this.licenseInfos.size()) { + return false; + } + Iterator iter = this.licenseInfos.iterator(); + while (iter.hasNext()) { + SPDXLicenseInfo li = iter.next(); + boolean found = false; + for (int i = 0; i < compInfos.length; i++) { + if (li.equals(compInfos[i])) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocument.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocument.java new file mode 100644 index 000000000..de8d14138 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocument.java @@ -0,0 +1,1356 @@ +/** + * Copyright (c) 2010, 2011 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.rdfparser; + +import java.util.ArrayList; +import java.util.HashSet; + +import com.google.common.collect.Sets; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +import java.util.regex.Matcher; + +import org.spdx.spdxspreadsheet.InvalidLicenseStringException; + + +/** + * + * Simple model for the SPDX Analysis document. The document is stored in a Jena RDF + * model which can be accessed through the model property. + * + * The class should be constructed using the SPDXDocumentFactory class + * + * The createSpdxDocument(uri) must be called first for a blank model + * + * The license, file, and package objects can be constructed then added to the model + * by using the set functions. + * + * The non-standard licenses must contain a unique ID of the form LicenseRef-NN where NN is a + * unique number. The method addNonStandardLicense(licenseText) can be called to + * create a new unique Non-Standard License. + * + * @author Gary O'Neall + * + */ +public class SPDXDocument implements SpdxRdfConstants { + + public static final String POINT_EIGHT_SPDX_VERSION = "SPDX-0.8"; + public static final String POINT_NINE_SPDX_VERSION = "SPDX-0.9"; + public static final String CURRENT_SPDX_VERSION = "SPDX-1.0"; + public static final String CURRENT_IMPLEMENTATION_VERSION = "0.9.4"; + + static Set SUPPORTED_SPDX_VERSIONS = Sets.newHashSet(); + + static { + SUPPORTED_SPDX_VERSIONS.add(CURRENT_SPDX_VERSION); + SUPPORTED_SPDX_VERSIONS.add(POINT_EIGHT_SPDX_VERSION); + SUPPORTED_SPDX_VERSIONS.add(POINT_NINE_SPDX_VERSION); + } + + /** + * Keeps tract of the next license reference number when generating the license ID's for + * non-standard licenses + */ + protected int nextLicenseRef = 1; + + /** + * Simple class representing an SPDX Package. This is stored in an RDF + * model. + * + * This package is initialized using an existing SPDXPackage in an + * RDF document by constructing the package with the node representing the + * SPDX package. + + * + * @author Gary O'Neall + * + */ + public class SPDXPackage { + private Node node = null; + /** + * Construct a new SPDX package and populate the properties from the node + * @param pkgNode Node in the RDF graph representing the SPDX package + */ + public SPDXPackage(Node pkgNode) { + this.node = pkgNode; + } + /** + * @return the declaredName + * @throws InvalidSPDXAnalysisException + */ + public String getDeclaredName() throws InvalidSPDXAnalysisException { + String[] declaredNames = findDocPropertieStringValues(this.node, PROP_PACKAGE_DECLARED_NAME); + if (declaredNames == null || declaredNames.length == 0) { + return null; + } + if (declaredNames.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one declared name for a package")); + } + return(declaredNames[0]); + } + + /** + * @param declaredName the declaredName to set + * @throws InvalidSPDXAnalysisException + */ + public void setDeclaredName(String declaredName) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_DECLARED_NAME); + addProperty(node, PROP_PACKAGE_DECLARED_NAME, new String[] {declaredName}); + } + /** + * @return the fileName + * @throws InvalidSPDXAnalysisException + */ + public String getFileName() throws InvalidSPDXAnalysisException { + String[] fileNames = findDocPropertieStringValues(this.node, PROP_PACKAGE_FILE_NAME); + if (fileNames == null || fileNames.length == 0) { + return null; + } + if (fileNames.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one machine name for a package")); + } + return fileNames[0]; + } + /** + * @param fileName the fileName to set + * @throws InvalidSPDXAnalysisException + */ + public void setFileName(String fileName) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_FILE_NAME); + addProperty(node, PROP_PACKAGE_FILE_NAME, new String[] {fileName}); + } + /** + * @return the sha1 + * @throws InvalidSPDXAnalysisException + */ + public String getSha1() throws InvalidSPDXAnalysisException { + + String retval = null; + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_CHECKSUM).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + SPDXChecksum cksum = new SPDXChecksum(model, t.getObject()); + if (cksum.getAlgorithm().equals(SPDXChecksum.ALGORITHM_SHA1)) { + retval = cksum.getValue(); + } + } + return retval; + } + /** + * @param sha1 the sha1 to set + * @throws InvalidSPDXAnalysisException + */ + public void setSha1(String sha1) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_CHECKSUM); + SPDXChecksum cksum = new SPDXChecksum(SPDXChecksum.ALGORITHM_SHA1, sha1); + Resource cksumResource = cksum.createResource(model); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_CHECKSUM); + s.addProperty(p, cksumResource); + } + /** + * @return the sourceInfo + * @throws InvalidSPDXAnalysisException + */ + public String getSourceInfo() throws InvalidSPDXAnalysisException { + String[] sourceInfos = findDocPropertieStringValues(this.node, PROP_PACKAGE_SOURCE_INFO); + if (sourceInfos == null || sourceInfos.length == 0) { + return null; + } + if (sourceInfos.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one source info for an SPDX package")); + } + return sourceInfos[0]; + } + /** + * @param sourceInfo the sourceInfo to set + * @throws InvalidSPDXAnalysisException + */ + public void setSourceInfo(String sourceInfo) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_SOURCE_INFO); + addProperty(node, PROP_PACKAGE_SOURCE_INFO, new String[] {sourceInfo}); + } + + /** + * @return Version information of the package + * @throws InvalidSPDXAnalysisException + */ + public String getVersionInfo() throws InvalidSPDXAnalysisException { + String[] versionInfos = findDocPropertieStringValues(this.node, PROP_PACKAGE_VERSION_INFO); + if (versionInfos == null || versionInfos.length == 0) { + return null; + } + if (versionInfos.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one version info for an SPDX package")); + } + return versionInfos[0]; + } + + /** + * Set the version information of the package + * @param versionInfo + * @throws InvalidSPDXAnalysisException + */ + public void setVersionInfo(String versionInfo) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_VERSION_INFO); + addProperty(node, PROP_PACKAGE_VERSION_INFO, new String[] {versionInfo}); + } + + /** + * @return the declaredLicenses + * @throws InvalidSPDXAnalysisException + */ + public SPDXLicenseInfo getDeclaredLicense() throws InvalidSPDXAnalysisException { + ArrayList alLic = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_DECLARED_LICENSE).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + if (alLic.size() > 1) { + throw(new InvalidSPDXAnalysisException("Too many declared licenses")); + } + if (alLic.size() == 0) { + return null; + } + return alLic.get(0); + } + /** + * @param declaredLicenses the declaredLicenses to set + * @throws InvalidSPDXAnalysisException + */ + public void setDeclaredLicense(SPDXLicenseInfo declaredLicense) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_DECLARED_LICENSE); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_DECLARED_LICENSE); + + Resource lic = declaredLicense.createResource(model); + s.addProperty(p, lic); + } + + + /** + * @return the detectedLicenses + * @throws InvalidSPDXAnalysisException + */ + public SPDXLicenseInfo getConcludedLicenses() throws InvalidSPDXAnalysisException { + ArrayList alLic = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_CONCLUDED_LICENSE).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + if (alLic.size() > 1) { + throw(new InvalidSPDXAnalysisException("Too many concluded licenses")); + } + if (alLic.size() == 0) { + return null; + } + return alLic.get(0); + } + /** + * @param detectedLicenses the detectedLicenses to set + * @throws InvalidSPDXAnalysisException + */ + public void setConcludedLicenses(SPDXLicenseInfo detectedLicenses) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_CONCLUDED_LICENSE); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_CONCLUDED_LICENSE); + Resource lic = detectedLicenses.createResource(model); + s.addProperty(p, lic); + } + /** + * @return the licenseComment + * @throws InvalidSPDXAnalysisException + */ + public String getLicenseComment() throws InvalidSPDXAnalysisException { + String[] comments = findDocPropertieStringValues(this.node, PROP_PACKAGE_LICENSE_COMMENT); + if (comments == null || comments.length == 0) { + return null; + } + if (comments.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one license comment for a package")); + } + return(comments[0]); + } + /** + * @param comments the license comments to set + * @throws InvalidSPDXAnalysisException + */ + public void setLicenseComment(String comments) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_LICENSE_COMMENT); + addProperty(node, PROP_PACKAGE_LICENSE_COMMENT, new String[] {comments}); + } + /** + * @return the declaredCopyright + * @throws InvalidSPDXAnalysisException + */ + public String getDeclaredCopyright() throws InvalidSPDXAnalysisException { + String[] copyrights = findDocPropertieStringValues(this.node, PROP_PACKAGE_DECLARED_COPYRIGHT); + if (copyrights == null || copyrights.length == 0) { + return null; + } + if (copyrights.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one declared copyright for a package")); + } + return(copyrights[0]); + } + /** + * @param declaredCopyright the declaredCopyright to set + * @throws InvalidSPDXAnalysisException + */ + public void setDeclaredCopyright(String declaredCopyright) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_DECLARED_COPYRIGHT); + addProperty(node, PROP_PACKAGE_DECLARED_COPYRIGHT, new String[] {declaredCopyright}); + } + /** + * @return the shortDescription + * @throws InvalidSPDXAnalysisException + */ + public String getShortDescription() throws InvalidSPDXAnalysisException { + String[] shortDescs = findDocPropertieStringValues(this.node, PROP_PACKAGE_SHORT_DESC); + if (shortDescs == null || shortDescs.length == 0) { + return null; + } + if (shortDescs.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one short description for a package")); + } + return(shortDescs[0]); + } + /** + * @param shortDescription the shortDescription to set + * @throws InvalidSPDXAnalysisException + */ + public void setShortDescription(String shortDescription) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_SHORT_DESC); + addProperty(node, PROP_PACKAGE_SHORT_DESC, new String[] {shortDescription}); + } + /** + * @return the description + * @throws InvalidSPDXAnalysisException + */ + public String getDescription() throws InvalidSPDXAnalysisException { + String[] desc = findDocPropertieStringValues(this.node, PROP_PACKAGE_DESCRIPTION); + if (desc == null || desc.length == 0) { + return null; + } + if (desc.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one description for a package")); + } + return(desc[0]); + } + /** + * @param description the description to set + * @throws InvalidSPDXAnalysisException + */ + public void setDescription(String description) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_DESCRIPTION); + addProperty(node, PROP_PACKAGE_DESCRIPTION, new String[] {description}); + } + + /** + * Set the originator + * @param originator Either a valid originator string or NOASSERTION + * @throws InvalidSPDXAnalysisException + */ + public void setOriginator(String originator) throws InvalidSPDXAnalysisException { + String error = SpdxVerificationHelper.verifyOriginator(originator); + if (error != null && !error.isEmpty()) { + throw(new InvalidSPDXAnalysisException(error)); + } + removeProperties(node, PROP_PACKAGE_ORIGINATOR); + addProperty(node, PROP_PACKAGE_ORIGINATOR, new String[] {originator}); + } + + /** + * Set the Supplier + * @param supplier Either a valid originator string or NOASSERTION + * @throws InvalidSPDXAnalysisException + */ + public void setSupplier(String supplier) throws InvalidSPDXAnalysisException { + String error = SpdxVerificationHelper.verifySupplier(supplier); + if (error != null && !error.isEmpty()) { + throw(new InvalidSPDXAnalysisException(error)); + } + removeProperties(node, PROP_PACKAGE_SUPPLIER); + addProperty(node, PROP_PACKAGE_SUPPLIER, new String[] {supplier}); + } + + public String getOriginator() throws InvalidSPDXAnalysisException { + String[] originators = findDocPropertieStringValues(this.node, PROP_PACKAGE_ORIGINATOR); + if (originators == null || originators.length == 0) { + return null; + } + if (originators.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one originator for a package")); + } + return(originators[0]); + } + + public String getSupplier() throws InvalidSPDXAnalysisException { + String[] suppliers = findDocPropertieStringValues(this.node, PROP_PACKAGE_SUPPLIER); + if (suppliers == null || suppliers.length == 0) { + return null; + } + if (suppliers.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one supplier for a package")); + } + return(suppliers[0]); + } + + /** + * @return the files + * @throws InvalidSPDXAnalysisException + */ + public SPDXFile[] getFiles() throws InvalidSPDXAnalysisException { + // files + ArrayList alFiles = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alFiles.add(new SPDXFile(model, t.getObject())); + } + SPDXFile[] retval = new SPDXFile[alFiles.size()]; + return alFiles.toArray(retval); + } + /** + * @param files the files to set + * @throws InvalidSPDXAnalysisException + */ + public void setFiles(SPDXFile[] files) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_FILE); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE); + Resource docResource = getResource(getSpdxDocNode()); + Property docP = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_FILE); + for (int i = 0; i < files.length; i++) { + Resource file = files[i].createResource(model); + s.addProperty(p, file); + docResource.addProperty(docP, file); + } + } + + public String getDownloadUrl() throws InvalidSPDXAnalysisException { + String[] urls = findDocPropertieStringValues(this.node, PROP_PACKAGE_DOWNLOAD_URL); + if (urls == null || urls.length == 0) { + return null; + } + if (urls.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one URL for a package")); + } + return(urls[0]); + } + + public void setDownloadUrl(String url) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_DOWNLOAD_URL); + addProperty(node, PROP_PACKAGE_DOWNLOAD_URL, new String[] {url}); + } + + public SpdxPackageVerificationCode getVerificationCode() throws InvalidSPDXAnalysisException { + SpdxPackageVerificationCode retval = null; + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_VERIFICATION_CODE).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + retval = new SpdxPackageVerificationCode(model, t.getObject()); + } + return retval; + } + + public void setVerificationCode(SpdxPackageVerificationCode verificationCode) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_VERIFICATION_CODE); + Resource verificationCodeResource = verificationCode.createResource(model); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_VERIFICATION_CODE); + s.addProperty(p, verificationCodeResource); + } + public SPDXPackageInfo getPackageInfo() throws InvalidSPDXAnalysisException { + return new SPDXPackageInfo(this.getDeclaredName(), this.getVersionInfo(), this.getFileName(), + this.getSha1(), this.getSourceInfo(), this.getDeclaredLicense(), + this.getConcludedLicenses(), this.getLicenseInfoFromFiles(), + this.getLicenseComment(), this.getDeclaredCopyright(), + this.getShortDescription(), this.getDescription(), this.getDownloadUrl(), + this.getVerificationCode(), this.getSupplier(), this.getOriginator()); + } + + public void setLicenseInfoFromFiles(SPDXLicenseInfo[] licenseInfo) throws InvalidSPDXAnalysisException { + removeProperties(node, PROP_PACKAGE_LICENSE_INFO_FROM_FILES); + Resource s = getResource(this.node); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_LICENSE_INFO_FROM_FILES); + for (int i = 0; i < licenseInfo.length; i++) { + Resource lic = licenseInfo[i].createResource(model); + s.addProperty(p, lic); + } + + } + + public SPDXLicenseInfo[] getLicenseInfoFromFiles() throws InvalidSPDXAnalysisException { + ArrayList alLic = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_LICENSE_INFO_FROM_FILES).asNode(); + Triple m = Triple.createMatch(this.node, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + SPDXLicenseInfo[] retval = new SPDXLicenseInfo[alLic.size()]; + retval = alLic.toArray(retval); + return retval; + } + /** + * @return + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + // name + try { + String name = this.getDeclaredName(); + if (name == null || name.isEmpty()) { + retval.add("Missing required name for package"); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid name: "+e.getMessage()); + } + // summary + try { + @SuppressWarnings("unused") + String summary = this.getShortDescription(); + //TODO: rdf has this as mandatory, optional in pdf - if mandatory add check + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid summary: "+e.getMessage()); + } + // description + try { + @SuppressWarnings("unused") + String description = this.getDescription(); + //TODO: rdf has this as mandatory, optional in pdf - if mandatory add check + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid description: "+e.getMessage()); + } + // download location + try { + String downloadLocation = this.getDownloadUrl(); + if (downloadLocation == null || downloadLocation.isEmpty()) { + retval.add("Missing required download location for package"); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid download location: "+e.getMessage()); + } + // checksum + try { + String checksum = this.getSha1(); + if (checksum != null && !checksum.isEmpty()) { + String verify = SpdxVerificationHelper.verifyChecksumString(checksum); + if (verify != null) { + retval.add("Package checksum error: "+verify); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid checksum: "+e.getMessage()); + } + // source Info - optional + try { + @SuppressWarnings("unused") + String sourceInfo = this.getSourceInfo(); + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package source info: "+e.getMessage()); + } + + // copyright text - mandatory + try { + String copyrightText = this.getDeclaredCopyright(); + if (copyrightText == null || copyrightText.isEmpty()) { + retval.add("Missing required package copyright text"); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package copyright: "+e.getMessage()); + } + + // license comments - optional + try { + @SuppressWarnings("unused") + String licenseComments = this.getLicenseComment(); + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid license comments: "+e.getMessage()); + } + + // license declared - mandatory - 1 (need to change return values) + try { + SPDXLicenseInfo declaredLicense = this.getDeclaredLicense(); + if (declaredLicense == null) { + retval.add("Missing required declared license"); + } else { + retval.addAll(declaredLicense.verify()); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package declared license: "+e.getMessage()); + } + + // license concluded - mandatory - 1 (need to change return values) + try { + SPDXLicenseInfo concludedLicense = this.getConcludedLicenses(); + if (concludedLicense == null) { + retval.add("Missing required concluded license"); + } else { + retval.addAll(concludedLicense.verify()); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package concluded license: "+e.getMessage()); + } + + // license infos from files - mandatory - 1 or more + try { + SPDXLicenseInfo[] licenseInfosFromFiles = this.getLicenseInfoFromFiles(); + if (licenseInfosFromFiles == null || licenseInfosFromFiles.length == 0) { + retval.add("Missing required license infos from files"); + } else { + for (int i = 0; i < licenseInfosFromFiles.length; i++) { + retval.addAll(licenseInfosFromFiles[i].verify()); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package license infos from files: "+e.getMessage()); + } + + // hasFiles mandatory one or more + try { + SPDXFile[] files = this.getFiles(); + if (files == null || files.length == 0) { + retval.add("Missing required package files"); + } else { + for (int i = 0; i < files.length; i++) { + retval.addAll(files[i].verify()); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package files: "+e.getMessage()); + } + + // verification code + SpdxPackageVerificationCode verificationCode = null; + try { + verificationCode = this.getVerificationCode(); + if (verificationCode == null) { + retval.add("Missing required package verification code."); + } else { + retval.addAll(verificationCode.verify()); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid package verification code: "+e.getMessage()); + } + + // supplier + String supplier = null; + try { + supplier = this.getSupplier(); + if (supplier != null) { + String error = SpdxVerificationHelper.verifySupplier(supplier); + if (error != null && !error.isEmpty()) { + retval.add("Supplier error - "+error); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid supplier: "+e.getMessage()); + } + + // originator + String originator = null; + try { + originator = this.getOriginator(); + if (originator != null) { + String error = SpdxVerificationHelper.verifySupplier(originator); + if (error != null && !error.isEmpty()) { + retval.add("Originator error - "+error); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid originator: "+e.getMessage()); + } + return retval; + } + } + + Model model; + SPDXPackage spdxPackage = null; + + public SPDXDocument(Model model) throws InvalidSPDXAnalysisException { + this.model = model; + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode != null) { // not empty - we should verify + verify(); + initializeNextLicenseRef(); + } + } + + /** + * Initialize the next license reference by scanning all of the existing non-standard licenses + * @throws InvalidSPDXAnalysisException + */ + private void initializeNextLicenseRef() throws InvalidSPDXAnalysisException { + initializeNextLicenseRef(this.getExtractedLicenseInfos()); + } + + private void initializeNextLicenseRef(SPDXNonStandardLicense[] existingLicenses) throws InvalidSPDXAnalysisException { + int highestNonStdLicense = 0; + for (int i = 0; i < existingLicenses.length; i++) { + int idNum = getLicenseRefNum(existingLicenses[i].getId()); + if (idNum > highestNonStdLicense) { + highestNonStdLicense = idNum; + } + } + this.nextLicenseRef = highestNonStdLicense + 1; + } + /** + * Parses a license ID and return the integer representing the ID number (e.g. N in LicenseRef-N) + * @param licenseID + * @return + * @throws InvalidSPDXAnalysisException + */ + public int getLicenseRefNum(String licenseID) throws InvalidSPDXAnalysisException { + Matcher matcher = LICENSE_ID_PATTERN.matcher(licenseID); + if (!matcher.matches()) { + throw(new InvalidSPDXAnalysisException("Invalid license ID found in the non-standard licenses: '"+licenseID+"'")); + } + int numGroups = matcher.groupCount(); + if (numGroups != 1) { + throw(new InvalidSPDXAnalysisException("Invalid license ID found in the non-standard licenses: '"+licenseID+"'")); + } + int idNum = Integer.decode(matcher.group(1)); + return idNum; + } + + public static String formNonStandardLicenseID(int idNum) { + return NON_STD_LICENSE_ID_PRENUM + String.valueOf(idNum); + } + + synchronized int getAndIncrementNextLicenseRef() { + int retval = this.nextLicenseRef; + this.nextLicenseRef++; + return retval; + } + + public String verifySpdxVersion(String spdxVersion) { + if (!spdxVersion.startsWith("SPDX-")) { + return "Invalid spdx version - must start with 'SPDX-'"; + } + Matcher docSpecVersionMatcher = SpdxRdfConstants.SPDX_VERSION_PATTERN.matcher(spdxVersion); + if (!docSpecVersionMatcher.matches()) { + return "Invalid spdx version format - must match 'SPDX-M.N'"; + } + return null; // if we got here, there is no problem + } + /** + * Verifies the spdx document + * @return error messages for any fields which do not match the spec. Return an empty array list if no issues. + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + // specVersion + String docSpecVersion = ""; // note - this is used later in verify to verify version specific info + try { + docSpecVersion = this.getSpdxVersion(); + if (docSpecVersion == null || docSpecVersion.isEmpty()) { + retval.add("Missing required SPDX version"); + } else { + String verify = verifySpdxVersion(docSpecVersion); + if (verify != null) { + retval.add(verify); + } else { + if (!SUPPORTED_SPDX_VERSIONS.contains(docSpecVersion)) { + retval.add("Version "+docSpecVersion+" is not supported by this version of the rdf parser"); + } + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid spec version: "+e.getMessage()); + } + // creationInfo + try { + SPDXCreatorInformation creator = this.getCreatorInfo(); + if (creator == null) { + retval.add("Missing required Creator"); + } else { + ArrayList creatorVerification = creator.verify(); + retval.addAll(creatorVerification); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid creator information: "+e.getMessage()); + } + // Package + try { + SPDXPackage sPkg = this.getSpdxPackage(); + if (sPkg == null) { + retval.add("Missing required SPDX Package"); + } else { + ArrayList packageVerification = sPkg.verify(); + retval.addAll(packageVerification); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid SPDX Package: "+e.getMessage()); + } + // Reviewers + try { + SPDXReview[] reviews = this.getReviewers(); + if (reviews != null) { + for (int i = 0; i < reviews.length; i++) { + ArrayList reviewerVerification = reviews[i].verify(); + retval.addAll(reviewerVerification); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid reviewers: "+e.getMessage()); + } + // Non standard licenses + try { + SPDXNonStandardLicense[] extractedLicInfos = this.getExtractedLicenseInfos(); + if (extractedLicInfos != null) { + for (int i = 0; i < extractedLicInfos.length; i++) { + ArrayList extractedLicInfoVerification = extractedLicInfos[i].verify(); + retval.addAll(extractedLicInfoVerification); + } + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid extracted licensing info: "+e.getMessage()); + } + // data license + if (!docSpecVersion.equals(POINT_EIGHT_SPDX_VERSION) && !docSpecVersion.equals(POINT_NINE_SPDX_VERSION)) { // added as a mandatory field in 1.0 + try { + SPDXStandardLicense dataLicense = this.getDataLicense(); + if (dataLicense == null) { + retval.add("Missing required data license"); + } + if (!dataLicense.getId().equals(SPDX_DATA_LICENSE_ID)) { + retval.add("Incorrect data license for SPDX document - found "+dataLicense.getId()+", expected "+SPDX_DATA_LICENSE_ID); + } + } catch (InvalidSPDXAnalysisException e) { + retval.add("Invalid data license: "+e.getMessage()); + } + } + return retval; + } + + /** + * @param propertyName + * @return + */ + /** + * Find all property string values belonging to the subject + * @param subject + * @param propertyName + * @return string values of the properties or null if the subject or propertyName is null + */ + private String[] findDocPropertieStringValues(Node subject, String propertyName) { + if (subject == null || propertyName == null) { + return null; + } + ArrayList alResult = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, propertyName).asNode(); + Triple m = Triple.createMatch(subject, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + if (t.getObject().isURI()) { + if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NONE)) { + alResult.add(SpdxRdfConstants.NONE_VALUE); + } else if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NOASSERTION)) { + alResult.add(SpdxRdfConstants.NOASSERTION_VALUE); + } else { + alResult.add(t.getObject().toString(false)); + } + } else { + alResult.add(t.getObject().toString(false)); + } + } + String[] retval = new String[alResult.size()]; + return alResult.toArray(retval); + } + + /** + * Remove all properties by the property name from the subject node + * @param node + * @param propertyName + * @throws InvalidSPDXAnalysisException + */ + private void removeProperties(Node subject, String propertyName) throws InvalidSPDXAnalysisException { + Property p = model.getProperty(SPDX_NAMESPACE, propertyName); + Resource s = getResource(subject); + model.removeAll(s, p, null); + + } + + private Resource getResource(Node node) throws InvalidSPDXAnalysisException { + Resource s; + if (node.isURI()) { + s = model.createResource(node.getURI()); + } else if (node.isBlank()) { + s = model.createResource(node.getBlankNodeId()); + } else { + throw(new InvalidSPDXAnalysisException("Node can not be a literal")); + } + return s; + } + + private void addProperty(Node subject, String propertyName, String[] propertyValue) throws InvalidSPDXAnalysisException { Resource s = getResource(subject); + for (int i = 0; i < propertyValue.length; i++) { + Property p = model.createProperty(SPDX_NAMESPACE, propertyName); + if (propertyValue[i].equals(SpdxRdfConstants.NONE_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NONE); + s.addProperty(p, r); + } else if (propertyValue[i].equals(SpdxRdfConstants.NOASSERTION_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NOASSERTION); + s.addProperty(p, r); + } else { + s.addProperty(p, propertyValue[i]); + } + } + } + + /** + * @return the spdxVersion or null if there is no SPDX document + * @throws InvalidSPDXAnalysisException + */ + public String getSpdxVersion() throws InvalidSPDXAnalysisException { + String[] versions = findDocPropertieStringValues(getSpdxDocNode(), PROP_SPDX_VERSION); + if (versions == null || versions.length == 0) { + return null; + } + if (versions.length > 1) { + throw(new InvalidSPDXAnalysisException("More than one version exists for the SPDX Document")); + } + return versions[0]; + } + + /** + * @param spdxVersion the spdxVersion to set + * @throws InvalidSPDXAnalysisException + */ + public void setSpdxVersion(String spdxVersion) throws InvalidSPDXAnalysisException { + String versionVerify = verifySpdxVersion(spdxVersion); + if (versionVerify != null && !versionVerify.isEmpty()) { + throw(new InvalidSPDXAnalysisException(versionVerify)); + } + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must create the SPDX document before setting spdxVersion")); + } + removeProperties(spdxDocNode, PROP_SPDX_VERSION); + addProperty(spdxDocNode, PROP_SPDX_VERSION, new String[] {spdxVersion}); + } + + public SPDXStandardLicense getDataLicense() throws InvalidSPDXAnalysisException { + ArrayList alLic = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_DATA_LICENSE).asNode(); + Triple m = Triple.createMatch(getSpdxDocNode(), p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + if (alLic.size() > 1) { + throw(new InvalidSPDXAnalysisException("Too many data licenses")); + } + if (alLic.size() == 0) { + throw(new InvalidSPDXAnalysisException("Missing required data license")); + } + if (!(alLic.get(0) instanceof SPDXStandardLicense)) { + throw(new InvalidSPDXAnalysisException("Incorrect license for datalicense - must be a standard SPDX license type")); + } + return (SPDXStandardLicense)(alLic.get(0)); + } + + public void setDataLicense(SPDXStandardLicense dataLicense) throws InvalidSPDXAnalysisException { + if (!dataLicense.getId().equals(SPDX_DATA_LICENSE_ID)) { + throw(new InvalidSPDXAnalysisException("Invalid data license for SPDX document - license must have ID "+SPDX_DATA_LICENSE_ID)); + } + removeProperties(getSpdxDocNode(), PROP_SPDX_DATA_LICENSE); + Resource s = getResource(getSpdxDocNode()); + Property p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_DATA_LICENSE); + + Resource lic = dataLicense.createResource(model); + s.addProperty(p, lic); + } + + public SPDXFile[] getFileReferences() throws InvalidSPDXAnalysisException { + ArrayList alFiles = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_FILE).asNode(); + Triple m = Triple.createMatch(getSpdxDocNode(), p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alFiles.add(new SPDXFile(model, t.getObject())); + } + SPDXFile[] retval = new SPDXFile[alFiles.size()]; + return alFiles.toArray(retval); + } + + @Deprecated + /** + * This method id deprecated - please use the getCreator() method for this information + * @return the The creators of the Analysis + * @throws InvalidSPDXAnalysisException + */ + public String[] getCreators() throws InvalidSPDXAnalysisException { + SPDXCreatorInformation creator = getCreatorInfo(); + if (creator != null && creator.getCreators() != null) { + return creator.getCreators(); + } else { + return null; + } + } + + public SPDXCreatorInformation getCreatorInfo() throws InvalidSPDXAnalysisException { + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("No SPDX Document was found. Can not access the creator information")); + } + ArrayList als = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO).asNode(); + Triple m = Triple.createMatch(spdxDocNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + als.add(new SPDXCreatorInformation(model, t.getObject())); + } + if (als.size() > 1) { + throw(new InvalidSPDXAnalysisException("Too many creation infos for document. Only one is allowed.")); + } + if (als.size() > 0) { + return als.get(0); + } else { + return null; + } + } + + /** + * @param creators the creators of the analysis + * @throws InvalidSPDXDocException + */ + public void setCreationInfo(SPDXCreatorInformation creator) throws InvalidSPDXAnalysisException { + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must have an SPDX document to set creationInfo")); + } + // delete any previous created + Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO); + Resource s = getResource(spdxDocNode); + model.removeAll(s, p, null); + // add the property + p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO); + s.addProperty(p, creator.createResource(model)); + } + + @Deprecated + /** + * This method id deprecated - please use the getCreator() method for this information + * @return the creator comments for the analysis + * @throws InvalidSPDXAnalysisException + */ + public String getCreatorComment() throws InvalidSPDXAnalysisException { + SPDXCreatorInformation creator = this.getCreatorInfo(); + if (creator != null) { + return creator.getComment(); + } else { + return null; + } + } + + /** + * @return the reviewers + * @throws InvalidSPDXAnalysisException + */ + public SPDXReview[] getReviewers() throws InvalidSPDXAnalysisException { + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must have an SPDX document to get reviewers")); + } + ArrayList als = new ArrayList(); + als.clear(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY).asNode(); + Triple m = Triple.createMatch(spdxDocNode, p, null); + ExtendedIteratortripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + als.add(new SPDXReview(model, t.getObject())); + } + SPDXReview[] reviewers = new SPDXReview[als.size()]; + reviewers = als.toArray(reviewers); + return reviewers; + } + + /** + * @param reviewers the reviewers to set + * @throws InvalidSPDXAnalysisException + */ + public void setReviewers(SPDXReview[] reviewers) throws InvalidSPDXAnalysisException { + if (reviewers.length > 0) { + ArrayList errors = new ArrayList(); + for (int i = 0;i < reviewers.length; i++) { + errors.addAll(reviewers[i].verify()); + } + if (errors.size() > 0) { + StringBuilder sb = new StringBuilder("Invalid reviewers due to the following errors in validation:\n"); + for (int i = 0; i < errors.size(); i++) { + sb.append(errors.get(i)); + sb.append('\n'); + } + throw(new InvalidSPDXAnalysisException(sb.toString())); + } + } + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must have an SPDX document to set reviewers")); + } + // delete any previous created + Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY); + Resource s = getResource(spdxDocNode); + model.removeAll(s, p, null); + // add the property + for (int i = 0; i < reviewers.length; i++) { + p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY); + s.addProperty(p, reviewers[i].createResource(model)); + } + } + + @Deprecated + /** + * This method id deprecated - please use the getCreator() method for this information + * @return the created + * @throws InvalidSPDXAnalysisException + */ + public String getCreated() throws InvalidSPDXAnalysisException { + SPDXCreatorInformation creator = this.getCreatorInfo(); + if (creator != null) { + return creator.getCreated(); + } else { + return null; + } + } + + /** + * @return the spdxPackage + * @throws InvalidSPDXAnalysisException + */ + public SPDXPackage getSpdxPackage() throws InvalidSPDXAnalysisException { + if (this.spdxPackage != null) { + return this.spdxPackage; + } + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must set an SPDX doc before getting an SPDX package")); + } + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE).asNode(); + Triple m = Triple.createMatch(spdxDocNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + SPDXPackage newSpdxPackage = null; + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + newSpdxPackage = new SPDXPackage(t.getObject()); + } + this.spdxPackage = newSpdxPackage; + return newSpdxPackage; + } + + /** + * Creates an empty SPDX package + * @param uri Unique URI representing the SPDX package + * @throws InvalidSPDXAnalysisException + */ + public void createSpdxPackage(String uri) throws InvalidSPDXAnalysisException { + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must create the SPDX document before creating an SPDX Package")); + } + // delete the previous SPDX package + Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE); + Resource s = getResource(getSpdxDocNode()); + model.removeAll(s, p, null); + p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE); + Resource pkgType = model.createResource(SPDX_NAMESPACE+CLASS_SPDX_PACKAGE); + Resource spdxPkg = model.createResource(uri, pkgType); + s.addProperty(p, spdxPkg); + this.spdxPackage = new SPDXPackage(spdxPkg.asNode()); + } + + public void createSpdxPackage() throws InvalidSPDXAnalysisException { + // generate a unique URI by appending a "?package" to the end of the doc URI + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must create the SPDX document before creating an SPDX Package")); + } + createSpdxPackage(spdxDocNode.getURI()+"?package"); + } + + /** + * @return the nonStandardLicenses + * @throws InvalidSPDXAnalysisException + */ + public SPDXNonStandardLicense[] getExtractedLicenseInfos() throws InvalidSPDXAnalysisException { + // nonStandardLicenses + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("No SPDX Document - can not get the Non Standard Licenses")); + } + ArrayList alLic = new ArrayList(); + Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_NONSTANDARD_LICENSES).asNode(); + Triple m = Triple.createMatch(spdxDocNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(new SPDXNonStandardLicense(model, t.getObject())); + } + SPDXNonStandardLicense[] nonStandardLicenses = new SPDXNonStandardLicense[alLic.size()]; + nonStandardLicenses = alLic.toArray(nonStandardLicenses); + return nonStandardLicenses; + } + + /** + * @param nonStandardLicenses the nonStandardLicenses to set + * @throws InvalidSPDXAnalysisException + */ + public void setExtractedLicenseInfos(SPDXNonStandardLicense[] nonStandardLicenses) throws InvalidSPDXAnalysisException { + ArrayList errors = new ArrayList(); + // verify the licenses + for (int i = 0;i < nonStandardLicenses.length; i++) { + errors.addAll(nonStandardLicenses[i].verify()); + } + if (errors.size() > 0) { + StringBuilder sb = new StringBuilder("Invalid extracted license infos due to the following verification failures:\n"); + for (int i = 0; i < errors.size(); i++) { + sb.append(errors.get(i)); + sb.append('\n'); + } + throw new InvalidSPDXAnalysisException(sb.toString()); + } + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + throw(new InvalidSPDXAnalysisException("Must create the SPDX document before setting Non-Standard Licenses")); + } + // validate the license ID's and update the next license ID property + initializeNextLicenseRef(nonStandardLicenses); + // delete the previous createdby's + Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_NONSTANDARD_LICENSES); + Resource s = getResource(getSpdxDocNode()); + model.removeAll(s, p, null); + for (int i = 0; i < nonStandardLicenses.length; i++) { + p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_NONSTANDARD_LICENSES); + s.addProperty(p, nonStandardLicenses[i].createResource(model)); + } + // need to re-update the max license ID + } + + /** + * Adds a new non-standard license containing the text provided. Forms the license ID + * from the next License ID available + * @param licenseText + * @return the newly created NonStandardLicense + * @throws InvalidSPDXAnalysisException + */ + public synchronized SPDXNonStandardLicense addNewExtractedLicenseInfo(String licenseText) throws InvalidSPDXAnalysisException { + int nextLicNum = this.getAndIncrementNextLicenseRef(); + String licenseID = formNonStandardLicenseID(nextLicNum); + SPDXNonStandardLicense retval = new SPDXNonStandardLicense(licenseID, licenseText); + Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_NONSTANDARD_LICENSES); + Resource s = getResource(getSpdxDocNode()); + s.addProperty(p, retval.createResource(model)); + return retval; + } + + /** + * @return the URI of the SPDX Document + */ + public String getSpdxDocUri() { + // populate the model + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode == null) { + return null; + } + return spdxDocNode.toString(false); + } + + /** + * @return the model + */ + public Model getModel() { + return model; + } + + /** + * @param model the model to set + */ + public void setModel(Model model) { + this.model = model; + } + + /** + * Creates a new empty SPDX Document. + * Note: Any previous SPDX documents will be deleted from the model to + * preserve the one and only one constraint. + * Note: Follow-up calls MUST be made to add the required properties for this + * to be a valid SPDX document + * @param uri URI for the SPDX Document + * @throws InvalidLicenseStringException + * @throws InvalidSPDXAnalysisException + */ + public void createSpdxAnalysis(String uri) throws InvalidSPDXAnalysisException { + Node spdxDocNode = getSpdxDocNode(); + if (spdxDocNode != null) { + // delete + model.removeAll(); + } + model.setNsPrefix("", SPDX_NAMESPACE); + Resource spdxAnalysisType = model.createResource(SPDX_NAMESPACE+CLASS_SPDX_ANALYSIS); + model.createResource(uri, spdxAnalysisType); + // add the default data license + SPDXStandardLicense dataLicense; + try { + dataLicense = (SPDXStandardLicense)(SPDXLicenseInfoFactory.parseSPDXLicenseString(SPDX_DATA_LICENSE_ID)); + } catch (InvalidLicenseStringException e) { + throw(new InvalidSPDXAnalysisException("Error generating the data license for the SPDX document")); + } + this.setDataLicense(dataLicense); + } + + /** + * @return the spdx doc node from the model + */ + private Node getSpdxDocNode() { + Node spdxDocNode = null; + Node rdfTypePredicate = this.model.getProperty(RDF_NAMESPACE, RDF_PROP_TYPE).asNode(); + Node spdxDocObject = this.model.getProperty(SPDX_NAMESPACE, CLASS_SPDX_ANALYSIS).asNode(); + Triple m = Triple.createMatch(null, rdfTypePredicate, spdxDocObject); + ExtendedIterator tripleIter = model.getGraph().find(m); // find the document + while (tripleIter.hasNext()) { + Triple docTriple = tripleIter.next(); + spdxDocNode = docTriple.getSubject(); + } + return spdxDocNode; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocumentFactory.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocumentFactory.java new file mode 100644 index 000000000..46d511100 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXDocumentFactory.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.regex.Pattern; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.util.FileManager; + +/** + * Factory for creating an SPDX Document from a variety of different sources + * @author Gary O'Neall + * + * + */ +public class SPDXDocumentFactory { + + /** + * Create a new SPDX Document populating the date from the existing model + * @param model + * @return + * @throws InvalidSPDXAnalysisException + */ + static SpdxRdfConstants createSpdxDocument(Model model) throws InvalidSPDXAnalysisException { + return new SPDXDocument(model); + } + + /** + * Create an SPDX Document from a file + * @param fileNameOrUrl local file name or Url containing the SPDX data. Can be in RDF/XML or RDFa format + * @return SPDX Document initialized with the exsiting data + * @throws IOException + * @throws InvalidSPDXAnalysisException + */ + public static SPDXDocument creatSpdxDocument(String fileNameOrUrl) throws IOException, InvalidSPDXAnalysisException { + try { + Class.forName("net.rootdev.javardfa.jena.RDFaReader"); + } catch(java.lang.ClassNotFoundException e) {} // do nothing + + Model model = ModelFactory.createDefaultModel(); + + InputStream spdxRdfInput = FileManager.get().open(fileNameOrUrl); + if (spdxRdfInput == null) + throw new FileNotFoundException("Unable to open \"" + fileNameOrUrl + "\" for reading"); + + model.read(spdxRdfInput, figureBaseUri(fileNameOrUrl), fileType(fileNameOrUrl)); + + return new SPDXDocument(model); + } + + private static String figureBaseUri(String src) { + try{ + URI s = new URI(src); + + if (null == s.getScheme()) + return "file://" + new File(src).getAbsoluteFile().toString().replace("\\", "/"); + else + return s.toString(); + + } catch(URISyntaxException e){ + return null; + } + } + + private static String fileType(String path) { + if (Pattern.matches("(?i:.*\\.x?html?$)", path)) + return "HTML"; + else + return "RDF/XML"; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXFile.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXFile.java new file mode 100644 index 000000000..d743c88cc --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXFile.java @@ -0,0 +1,483 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * @author Source Auditor + * + */ +public class SPDXFile { + private Node node = null; + private Model model = null; + private String name; + private SPDXLicenseInfo concludedLicenses; + private String sha1; + private String type; + private SPDXLicenseInfo[] seenLicenses; + private String licenseComments; + private String copyright; + private DOAPProject[] artifactOf; + /** + * Construct an SPDX File form the fileNode + * @param fileNode RDF Graph node representing the SPDX File + * @throws InvalidSPDXAnalysisException + */ + public SPDXFile(Model model, Node fileNode) throws InvalidSPDXAnalysisException { + this.node = fileNode; + this.model = model; + // name + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_NAME).asNode(); + Triple m = Triple.createMatch(fileNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.name = t.getObject().toString(false); + } + // checksum - sha1 + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_CHECKSUM).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + SPDXChecksum cksum = new SPDXChecksum(model, t.getObject()); + if (cksum.getAlgorithm().equals(SPDXChecksum.ALGORITHM_SHA1)) { + this.sha1 = cksum.getValue(); + } + } + // type + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_TYPE).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.type = t.getObject().toString(false); + } + // concluded License + ArrayList alLic = new ArrayList(); + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LICENSE).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + if (alLic.size() > 1) { + throw(new InvalidSPDXAnalysisException("Too many concluded licenses for file")); + } + if (alLic.size() == 0) { + throw(new InvalidSPDXAnalysisException("Missing required concluded license")); + } + this.concludedLicenses = alLic.get(0); + // seenLicenses + alLic.clear(); + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_SEEN_LICENSE).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alLic.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + this.seenLicenses = alLic.toArray(new SPDXLicenseInfo[alLic.size()]); + //licenseComments + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LIC_COMMENTS).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.licenseComments = t.getObject().toString(false); + } + //copyright + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_COPYRIGHT).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + if (t.getObject().isURI()) { + // check for standard value types + if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NOASSERTION)) { + this.copyright = SpdxRdfConstants.NOASSERTION_VALUE; + } else if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NONE)) { + this.copyright = SpdxRdfConstants.NONE_VALUE; + } else { + this.copyright = t.getObject().toString(false); + } + } else { + this.copyright = t.getObject().toString(false); + } + } + //artifactOf + ArrayList alProjects = new ArrayList(); + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_ARTIFACTOF).asNode(); + m = Triple.createMatch(fileNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + alProjects.add(new DOAPProject(model, t.getObject())); + } + this.artifactOf = alProjects.toArray(new DOAPProject[alProjects.size()]); + } + + public Resource createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + SpdxRdfConstants.CLASS_SPDX_FILE); + Resource retval = model.createResource(type); + populateModel(model, retval); + return retval; + } + + /** + * Populates a Jena RDF model with the information from this file declaration + * @param licenseResource + * @param model + */ + private void populateModel(Model model, Resource fileResource) { + // name + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_NAME); + fileResource.addProperty(p, this.getName()); + + if (this.sha1 != null) { + // sha1 + SPDXChecksum cksum = new SPDXChecksum(SPDXChecksum.ALGORITHM_SHA1, sha1); + Resource cksumResource = cksum.createResource(model); + + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_CHECKSUM); + fileResource.addProperty(p, cksumResource); + } + // type + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_TYPE); + fileResource.addProperty(p, this.getType()); + + // detectedLicense + if (this.concludedLicenses != null) { + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LICENSE); + Resource lic = this.concludedLicenses.createResource(model); + fileResource.addProperty(p, lic); + } + + // seenLicenses + if (this.seenLicenses != null && this.seenLicenses.length > 0) { + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_SEEN_LICENSE); + for (int i = 0; i < this.seenLicenses.length; i++) { + Resource lic = this.seenLicenses[i].createResource(model); + fileResource.addProperty(p, lic); + } + } + //licenseComments + if (this.licenseComments != null) { + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LIC_COMMENTS); + fileResource.addProperty(p, this.getLicenseComments()); + } + //copyright + if (this.copyright != null) { + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_COPYRIGHT); + if (copyright.equals(SpdxRdfConstants.NONE_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NONE); + fileResource.addProperty(p, r); + } else if (copyright.equals(SpdxRdfConstants.NOASSERTION_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NOASSERTION); + fileResource.addProperty(p, r); + } else { + fileResource.addProperty(p, this.getCopyright()); + } + } + + //artifactof + if (this.artifactOf != null) { + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_ARTIFACTOF); + for (int i = 0; i < artifactOf.length; i++) { + Resource projectResource = artifactOf[i].createResource(model); + fileResource.addProperty(p, projectResource); + } + } + + this.model = model; + this.node = fileResource.asNode(); + } + public SPDXFile(String name, String type, String sha1, + SPDXLicenseInfo concludedLicenses, + SPDXLicenseInfo[] seenLicenses, String licenseComments, + String copyright, DOAPProject[] artifactOf) { + this.name = name; + this.type = type; + this.sha1 = sha1; + this.concludedLicenses = concludedLicenses; + this.seenLicenses = seenLicenses; + this.licenseComments = licenseComments; + this.copyright = copyright; + this.artifactOf = artifactOf; + } + /** + * @return the seenLicenses + */ + public SPDXLicenseInfo[] getSeenLicenses() { + return seenLicenses; + } + /** + * @param seenLicenses the seenLicenses to set + */ + public void setSeenLicenses(SPDXLicenseInfo[] seenLicenses) { + this.seenLicenses = seenLicenses; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_SEEN_LICENSE); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_SEEN_LICENSE); + + for (int i = 0; i < seenLicenses.length; i++) { + Resource lic = seenLicenses[i].createResource(model); + fileResource.addProperty(p, lic); + } + } + } + /** + * @return the licenseComments + */ + public String getLicenseComments() { + return licenseComments; + } + /** + * @param licenseComments the licenseComments to set + */ + public void setLicenseComments(String licenseComments) { + this.licenseComments = licenseComments; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LIC_COMMENTS); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LIC_COMMENTS); + fileResource.addProperty(p, this.getLicenseComments()); + } + } + /** + * @return the copyright + */ + public String getCopyright() { + return copyright; + } + /** + * @param copyright the copyright to set + */ + public void setCopyright(String copyright) { + this.copyright = copyright; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_COPYRIGHT); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_COPYRIGHT); + if (copyright.equals(SpdxRdfConstants.NONE_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NONE); + fileResource.addProperty(p, r); + } else if (copyright.equals(SpdxRdfConstants.NOASSERTION_VALUE)) { + Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NOASSERTION); + fileResource.addProperty(p, r); + } else { + fileResource.addProperty(p, this.getCopyright()); + } + } + } + + + /** + * @return the name + */ + public String getName() { + return this.name; + } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_NAME); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_NAME); + fileResource.addProperty(p, this.getName()); + } + } + /** + * @return the fileLicenses + */ + public SPDXLicenseInfo getConcludedLicenses() { + return this.concludedLicenses; + } + /** + * @param fileLicenses the fileLicenses to set + */ + public void setConcludedLicenses(SPDXLicenseInfo fileLicenses) { + this.concludedLicenses = fileLicenses; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LICENSE); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_LICENSE); + Resource lic = fileLicenses.createResource(model); + fileResource.addProperty(p, lic); + } + } + /** + * @return the sha1 + */ + public String getSha1() { + return this.sha1; + } + /** + * @param sha1 the sha1 to set + */ + public void setSha1(String sha1) { + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_CHECKSUM); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + SPDXChecksum cksum = new SPDXChecksum(SPDXChecksum.ALGORITHM_SHA1, sha1); + Resource cksumResource = cksum.createResource(model); + + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_CHECKSUM); + fileResource.addProperty(p, cksumResource); + } + } + /** + * @return the type + */ + public String getType() { + return this.type; + } + /** + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + if (this.model != null && this.node != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_TYPE); + Resource fileResource = model.createResource(node.getURI()); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_TYPE); + fileResource.addProperty(p, this.getType()); + } + } + + /** + * @return the artifactOf + */ + public DOAPProject[] getArtifactOf() { + return artifactOf; + } + + /** + * @param artifactOf the artifactOf to set + */ + public void setArtifactOf(DOAPProject[] artifactOf) { + this.artifactOf = artifactOf; + if (this.model != null && this.name != null) { + Resource fileResource = model.createResource(node.getURI()); + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_ARTIFACTOF); + model.removeAll(fileResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_FILE_ARTIFACTOF); + for (int i = 0; i < artifactOf.length; i++) { + // we need to check on these if it already exists + Resource projectResource = null; + String uri = artifactOf[i].getProjectUri(); + if (uri != null) { + projectResource = model.createResource(uri); + } else { + projectResource = artifactOf[i].createResource(model); + } + fileResource.addProperty(p, projectResource); + } + } + + } + + /** + * @return + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + // fileName + String fileName = this.getName(); + if (fileName == null || fileName.isEmpty()) { + retval.add("Missing required name for file"); + fileName = "UNKNOWN"; + } + // fileType + //TODO: Resolve whether mandatory or not + String fileType = this.getType(); + if (fileType == null || fileType.isEmpty()) { + retval.add("Missing required file type"); + } else { + String verifyFileType = SpdxVerificationHelper.verifyFileType(fileType); + if (verifyFileType != null) { + retval.add(verifyFileType + "; File - "+fileName); + } + } + // copyrightText + //TODO: Resolve whether mandatory or not + String copyrightText = this.getCopyright(); + if (copyrightText == null || copyrightText.isEmpty()) { + retval.add("Missing required copyright text for file "+fileName); + } + // license comments + @SuppressWarnings("unused") + String comments = this.getLicenseComments(); + // license concluded + SPDXLicenseInfo concludedLicense = this.getConcludedLicenses(); + if (concludedLicense == null) { + retval.add("Missing required concluded license for file "+fileName); + } else { + retval.addAll(concludedLicense.verify()); + } + // license info in files + SPDXLicenseInfo[] licenseInfosInFile = this.getSeenLicenses(); + if (licenseInfosInFile == null || licenseInfosInFile.length == 0) { + retval.add("Missing required license infos in file for file "+fileName); + } else { + for (int i = 0; i < licenseInfosInFile.length; i++) { + retval.addAll(licenseInfosInFile[i].verify()); + } + } + // checksum + String checksum = this.getSha1(); + if (checksum == null || checksum.isEmpty()) { + retval.add("Missing required checksum for file "+fileName); + } else { + String verify = SpdxVerificationHelper.verifyChecksumString(checksum); + if (verify != null) { + retval.add(verify + "; file "+fileName); + } + } + // artifactOf - limit to one + DOAPProject[] projects = this.getArtifactOf(); + if (projects != null) { + if (projects.length > 1) { + retval.add("To many artifact of's - limit to one per file. File: "+fileName); + } + for (int i = 0;i < projects.length; i++) { + retval.addAll(projects[i].verify()); + } + } + return retval; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicense.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicense.java new file mode 100644 index 000000000..64146245b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicense.java @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Describes a license + * + * All licenses have an ID and text. Subclasses should extend this class to add + * additional properties. + * + * @author Gary O'Neall + * + */ +public abstract class SPDXLicense extends SPDXLicenseInfo { + protected String id; + protected String text; + + /** + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + SPDXLicense(Model model, Node licenseInfoNode) throws InvalidSPDXAnalysisException { + super(model, licenseInfoNode); + // id + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_ID).asNode(); + Triple m = Triple.createMatch(licenseInfoNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.id = t.getObject().toString(false); + } + // text + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_TEXT).asNode(); + m = Triple.createMatch(licenseInfoNode, p, null); + tripleIter = model.getGraph().find(m); + // The following Kludge is to workaround a bug where the standard license HTML + // did not have the correct property name + //TODO: Remove kludge once the website is updated + // BEGIN KLUDGE + if (!tripleIter.hasNext()) { + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, "LicenseText").asNode(); + m = Triple.createMatch(licenseInfoNode, p, null); + tripleIter = model.getGraph().find(m); + } + // END KLUDGE + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.text = t.getObject().toString(false); + } + } + + SPDXLicense(String id, String text) { + super(); + this.id = id; + this.text = text; + } + /** + * @return the id + */ + public String getId() { + return this.id; + } + + /** + * @param id the id to set + */ + public void setId(String id) { + this.id = id; + if (licenseInfoNode != null) { + // delete any previous created + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_ID); + model.removeAll(resource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_ID); + resource.addProperty(p, id); + } + } + + /** + * @return the text + */ + public String getText() { + return this.text; + } + + /** + * @param text the text to set + */ + public void setText(String text) { + this.text = text; + if (this.licenseInfoNode != null) { + // delete any previous created + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_TEXT); + model.removeAll(resource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_TEXT); + resource.addProperty(p, text); + } + } + + /** + * Create a basic SPDXLicense resource of a given type + * If a license with this ID already exists in the model, then that resource + * is returned. No checking is done to make sure the text matches. ID's are + * assumed to be unique. + * NOTE: the type must be a subclass of SPDXLicense + * @param model + * @param uri + * @param typeURI + * @return + */ + protected Resource _createResource(Model model, Resource type, String uri) { + Resource r = null; + if (id != null) { + // check to see if it exists + Property idProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_LICENSE_ID); + Property typeProperty = this.model.getProperty(SpdxRdfConstants.RDF_NAMESPACE, + SpdxRdfConstants.RDF_PROP_TYPE); + Triple m = Triple.createMatch(null, idProperty.asNode(), null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + if (t.getObject().toString(false).equals(this.id)) { + Triple typeMatch = Triple.createMatch(t.getSubject(), typeProperty.asNode(), type.asNode()); + ExtendedIterator typeTripleIter = model.getGraph().find(typeMatch); + if (typeTripleIter.hasNext()) { + // found it + if (t.getSubject().isURI()) { + r = model.createResource(t.getSubject().getURI()); + } else if (t.getSubject().isBlank()) { + r = model.createResource(t.getSubject().getBlankNodeId()); + } + } + } + } + } + if (r == null) { + // need to create it + if (uri == null || uri.isEmpty()) { + r = model.createResource(type); + } else { + r = model.createResource(uri, type); + } + if (id != null) { + Property idProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_LICENSE_ID); + r.addProperty(idProperty, this.id); + } + if (this.text != null) { + Property textProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_LICENSE_TEXT); + r.addProperty(textProperty, this.text); + } + } + return r; + } + + @Override + public boolean equals(Object comp) { + if (!(comp instanceof SPDXLicense)) { + return false; + } + SPDXLicense compl = (SPDXLicense)comp; + return compl.getId().equals(this.getId()); + } + + /** + * @param model + * @param type + * @return + */ + public Resource _createResource(Model model, Resource type) { + return _createResource(model, type, null); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfo.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfo.java new file mode 100644 index 000000000..e0f57613e --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfo.java @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * This abstract class represents several ways of describing licensing information. + * License info can be described as a set of conjunctive licenses (where all licenses + * terms must apply), a set of disjunctive licenses (where there is a choice of one + * license among the set described) or a specific license. The specific license can + * be an SPDX standard license or a non-standard license. + * @author Gary O'Neall + * + */ +public abstract class SPDXLicenseInfo { + + //TODO: Consider adding a comment text string + + Model model = null; + Node licenseInfoNode = null; + Resource resource = null; + /** + * Create a new LicenseInfo object where the information is copied from + * the model at the LicenseInfo node + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + SPDXLicenseInfo(Model model, Node licenseInfoNode) throws InvalidSPDXAnalysisException { + this.model = model; + this.licenseInfoNode = licenseInfoNode; + resource = convertToResource(model, licenseInfoNode); + } + + /** + * Convert a node to a resource + * @param cmodel + * @param cnode + * @return + * @throws InvalidSPDXAnalysisException + */ + private Resource convertToResource(Model cmodel, Node cnode) throws InvalidSPDXAnalysisException { + if (cnode.isBlank()) { + return cmodel.createResource(cnode.getBlankNodeId()); + } else if (cnode.isURI()) { + return cmodel.createResource(cnode.getURI()); + } else { + throw(new InvalidSPDXAnalysisException("Can not create a license from a literal")); + } + } + + + SPDXLicenseInfo() { + this.model = null; + this.licenseInfoNode = null; + this.resource = null; + } + + /** + * If a resource does not already exist in this model for this object, + * create a new resource and populate it. If the resource does exist, + * return the existing resource. + * @param model + * @return resource created from the model + */ + public Resource createResource(Model model) { + if (this.model != null && + this.model.equals(model) && + this.licenseInfoNode != null && + this.resource != null) { + return resource; + } else { + this.model = model; + Resource retval = _createResource(model); + this.licenseInfoNode = retval.asNode(); + this.resource = retval; + return retval; + } + } + + /** + * Internal implementation of create resource which is subclass specific + * @param model + * @return + */ + protected abstract Resource _createResource(Model model); + + // force subclasses to implement toString + public abstract String toString(); + + // force subclasses to implement equals + public abstract boolean equals(Object o); + + /** + * @return + */ + public abstract ArrayList verify(); +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfoFactory.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfoFactory.java new file mode 100644 index 000000000..146bedbb3 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseInfoFactory.java @@ -0,0 +1,541 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +import org.spdx.spdxspreadsheet.InvalidLicenseStringException; +import org.spdx.rdfparser.SpdxRdfConstants; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.FileManager; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Factory for creating SPDXLicenseInfo objects from a Jena model + * @author Gary O'Neall + * + */ +public class SPDXLicenseInfoFactory { + + static final String[] STANDARD_LICENSE_IDS = new String[] { + "AFL-3","AFL-1.1","AFL-1.2","AFL-2","AFL-2.1","APL-1", + "Apache-1","Apache-1.1","Apache-2","APSL-1","APSL-1.1", + "APSL-1.2","APSL-2","Artistic-1","Artistic-2","AAL", + "BSL-1","BSD-2-Clause","BSD-3-Clause","BSD-4-Clause", + "CECILL-1","CECILL-2","CECILL-B","CECILL-C","ClArtistic", + "CDDL-1","CPAL-1","CPL-1","CATOSL-1.1","CC-BY-1","CC-BY-2", + "CC-BY-2.5","CC-BY-3","CC-BY-ND-1","CC-BY-ND-2","CC-BY-ND-2.5", + "CC-BY-ND-3","CC-BY-NC-1","CC-BY-NC-2","CC-BY-NC-2.5","CC-BY-NC-3", + "CC-BY-NC-ND-1","CC-BY-NC-ND-2","CC-BY-NC-ND-2.5","CC-BY-NC-ND-3", + "CC-BY-NC-SA-1","CC-BY-NC-SA-2","CC-BY-NC-SA-2.5","CC-BY-NC-SA-3", + "CC-BY-SA-1","CC-BY-SA-2","CC-BY-SA-2.5","CC-BY-SA-3","CUA-OPL-1", + "EPL-1","eCos-2","ECL-1","ECL-2","EFL-1","EFL-2","Entessa", + "ErlPL-1.1","EUDatagrid","EUPL-1","EUPL-1.1","Fair","Frameworx-1", + "AGPL-3","GFDL-1.2","GFDL-1.2","GFDL-1.3","GPL-1","GPL-1+", + "GPL-2","GPL-2+","GPL-2-with-autoconf-exception","GPL-2-with-bison-exception", + "GPL-2-with-classpath-exception","GPL-2-with-GCC-exception", + "GPL-2-with-font-exception","GPL-3","GPL-3+","GPL-3-with-autoconf-exception", + "GPL-3-with-GCC-exception","LGPL-2.1","LGPL-2.1+","LGPL-3", + "LGPL-3+","LGPL-2","LGPL-2+","LGPL+","gSOAP-1.3b","HPND", + "IPL-1","IPA","ISC","LPPL-1","LPPL-1.1","LPPL-1.2","LPPL-1.3c", + "Libpng","LPL-1.02","MS-PL","MS-RL","MirOS","MIT","Motosoto", + "MPL-1","MPL-1.1","Multics","NASA-1.3","Nauman","NGPL","Nokia", + "NPOSL-3","NTP","OCLC-2","OGTSL","OSL-1","OSL-2","OSL-3","OLDAP-2.8", + "OpenSSL","PHP-3","PostgreSQL","Python-CNRI","Python","QPL-1", "PDDL-1.0", + "RPSL-1","RPL-1.5","RHeCos-1.1","RSCPL","Ruby","OFL-1.1","Simple-2", + "Sleepycat","SugarCRM-1.1.3","SPL","Watcom-1","NCSA","VSL-1", + "W3C","WXwindows","Xnet","XFree86-1.1","YPL-1.1","Zimbra-1.3", + "Zlib","ZPL-1.1","ZPL-2","ZPL-2.1" + }; + + static final String STANDARD_LICENSE_ID_URL = "http://spdx.org/licenses/"; + + + public static final String NOASSERTION_LICENSE_NAME = "NOASSERTION"; + public static final String NONE_LICENSE_NAME = "NONE"; + + public static final String STANDARD_LICENSE_URI_PREFIX = "http://spdx.org/licenses/"; + private static final String STANDARD_LICENSE_RDF_LOCAL_DIR = "resources" + "/" + "stdlicenses"; + + private static final String STANDARD_LICENSE_RDF_LOCAL_FILENAME = STANDARD_LICENSE_RDF_LOCAL_DIR + "/" + "index.html"; + + private static Model standardLicenseModel = null; + +static final Set STANDARD_LICENSE_ID_SET = Sets.newHashSet(); + + static Map STANDARD_LICENSES = null; + + static { + loadStdLicenseIDs(); + } + + static final Set STANDARD_LICENSE_ID_URLS_SET = Sets.newHashSet(); + + static { + for (int i = 0; i < STANDARD_LICENSE_IDS.length; i++) { + STANDARD_LICENSE_ID_URLS_SET.add(STANDARD_LICENSE_ID_URL+STANDARD_LICENSE_IDS[i]); + } + } + + /** + * Create the appropriate SPDXLicenseInfo from the model and node provided. + * The appropriate SPDXLicenseInfo subclass object will be chosen based on + * the class (rdf type) of the node. If there is no rdf type, then the + * license ID is parsed to determine the type + * @param model + * @param node + * @return + */ + public static SPDXLicenseInfo getLicenseInfoFromModel(Model model, Node node) throws InvalidSPDXAnalysisException { + if (!node.isURI() && !node.isBlank()) { + throw(new InvalidSPDXAnalysisException("Can not create a LicenseInfo from a literal node")); + } + // check to see if it is a "standard" type of license (NONESEEN, NONE, NOTANALYZED, or STANDARD_LICENSE) + if (node.isURI()) { + if (node.getURI().equals(SpdxRdfConstants.SPDX_NAMESPACE+SpdxRdfConstants.TERM_LICENSE_NONE)) { + return new SPDXNoneLicense(model, node); + } else if (node.getURI().equals(SpdxRdfConstants.SPDX_NAMESPACE+SpdxRdfConstants.TERM_LICENSE_NOASSERTION)) { + return new SpdxNoAssertionLicense(model, node); + } else if (node.getURI().startsWith(STANDARD_LICENSE_URI_PREFIX)) { + // try to fetch the standard license from the model + try { + return getLicenseFromStdLicModel(node.getURI()); + } catch (Exception ex) { + // ignore for now - we'll try to get the standard license from the information in the model itself if it exists + } + } + } + SPDXLicenseInfo retval = getLicenseInfoByType(model, node); + if (retval == null) { + retval = getLicenseInfoById(model, node); + } + if (retval == null) { + throw(new InvalidSPDXAnalysisException("Could not determine the type for a license")); + } + return retval; + } + + /** + * @param uri + * @return + * @throws InvalidSPDXAnalysisException + */ + protected static SPDXStandardLicense getLicenseFromStdLicModel(String uri) throws InvalidSPDXAnalysisException { + String id = uri.substring(STANDARD_LICENSE_URI_PREFIX.length()); + if (STANDARD_LICENSES.containsKey(id)) { + return STANDARD_LICENSES.get(id); + } + Model licenseModel = getLicenseModel(uri); + if (licenseModel == null) { + throw(new InvalidSPDXAnalysisException("No standard license was found at "+uri)); + } + Resource licResource = licenseModel.getResource(uri); + if (licResource == null || !licenseModel.containsResource(licenseModel.asRDFNode(licResource.asNode()))) { + throw(new InvalidSPDXAnalysisException("No standard license was found at "+uri)); + } + SPDXStandardLicense retval = new SPDXStandardLicense(licenseModel, licResource.asNode()); + STANDARD_LICENSES.put(id, retval); + return retval; + } + + /** + * @param uri + * @return + * @throws NoStandardLicenseRdfModel + */ + private static Model getLicenseModel(String uri) throws NoStandardLicenseRdfModel { + try { + Class.forName("net.rootdev.javardfa.jena.RDFaReader"); + } catch(java.lang.ClassNotFoundException e) { + // do nothing + } + Model retval = ModelFactory.createDefaultModel(); + InputStream in = null; + String prefix = null; + try { + try { + prefix = uri; + in = FileManager.get().open(uri); + } catch(Exception ex) { + in = null; + } + if (in == null) { + // need to fetch from the local file system + String id = uri.substring(STANDARD_LICENSE_URI_PREFIX.length()); + String fileName = STANDARD_LICENSE_RDF_LOCAL_DIR + File.separator + id; +// prefix = "file://"+fileName.replace("\\", "/"); + in = FileManager.get().open(fileName); + if (in == null) { + throw(new NoStandardLicenseRdfModel("Standard license "+uri+" could not be read.")); + } + } + retval.read(in, prefix, "HTML"); + return retval; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + + } + } + } + } + + private static Model getStandardLicenseModel() throws InvalidSPDXAnalysisException { + if (standardLicenseModel == null) { + loadStandardLicenseModel(); + } + return standardLicenseModel; + } + + /** + * Load a standard license model from the index page + */ + private static void loadStandardLicenseModel() throws InvalidSPDXAnalysisException { + try { + Class.forName("net.rootdev.javardfa.jena.RDFaReader"); + } catch(java.lang.ClassNotFoundException e) { + // do nothing + } + + Model myStdLicModel = ModelFactory.createDefaultModel(); // don't use the static model to remove any possible timing windows while we are creating + + String base = STANDARD_LICENSE_URI_PREFIX+"index.html"; + InputStream licRdfInput = FileManager.get().open(STANDARD_LICENSE_URI_PREFIX+"index.html"); + try { + String fileType = "HTML"; + if (licRdfInput == null) { + // need to load a static copy + base = "file://"+STANDARD_LICENSE_RDF_LOCAL_FILENAME; + licRdfInput = FileManager.get().open(STANDARD_LICENSE_RDF_LOCAL_FILENAME); + if (licRdfInput == null) { + throw new NoStandardLicenseRdfModel("Unable to open standard license from website or from local file"); + } + } + try { + myStdLicModel.read(licRdfInput, base, fileType); + } catch(Exception ex) { + throw new NoStandardLicenseRdfModel("Unable to read the standard license model", ex); + } + standardLicenseModel = myStdLicModel; + } finally { + if (licRdfInput != null) { + try { + licRdfInput.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + static void loadStdLicenseIDs() { + STANDARD_LICENSES = Maps.newHashMap(); + try { + Model stdLicenseModel = getStandardLicenseModel(); + Node p = stdLicenseModel.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_ID).asNode(); + Triple m = Triple.createMatch(null, p, null); + ExtendedIterator tripleIter = stdLicenseModel.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + STANDARD_LICENSE_ID_SET.add(t.getObject().toString(false)); + } + } catch (Exception ex) { + + for (int i = 0; i < STANDARD_LICENSE_IDS.length; i++) { + STANDARD_LICENSE_ID_SET.add(STANDARD_LICENSE_IDS[i]); + } + } + } + + /** + * @param model + * @param node + * @return + * @throws InvalidSPDXAnalysisException + */ + private static SPDXLicenseInfo getLicenseInfoById(Model model, Node node) throws InvalidSPDXAnalysisException { + Node licenseIdPredicate = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_ID).asNode(); + Triple m = Triple.createMatch(node, licenseIdPredicate, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple triple = tripleIter.next(); + String id = triple.getObject().toString(false); + if (tripleIter.hasNext()) { + throw(new InvalidSPDXAnalysisException("More than one ID associated with license "+id)); + } + if (isStandardLicenseID(id)) { + return new SPDXStandardLicense(model, node); + } else if (id.startsWith(SpdxRdfConstants.NON_STD_LICENSE_ID_PRENUM)) { + return new SPDXNonStandardLicense(model, node); + } else { + // could not determine the type from the ID + // could be a conjunctive or disjunctive license ID + return null; + } + } else { + throw(new InvalidSPDXAnalysisException("No ID associated with a license")); + } + } + + /** + * @param model + * @param node + * @return + * @throws InvalidSPDXAnalysisException + */ + private static SPDXLicenseInfo getLicenseInfoByType(Model model, Node node) throws InvalidSPDXAnalysisException { + // find the subclass + Node rdfTypePredicate = model.getProperty(SpdxRdfConstants.RDF_NAMESPACE, + SpdxRdfConstants.RDF_PROP_TYPE).asNode(); + Triple m = Triple.createMatch(node, rdfTypePredicate, null); + ExtendedIterator tripleIter = model.getGraph().find(m); // find the type(s) + if (tripleIter.hasNext()) { + Triple triple = tripleIter.next(); + if (tripleIter.hasNext()) { + throw(new InvalidSPDXAnalysisException("More than one type associated with a licenseInfo")); + } + Node typeNode = triple.getObject(); + if (!typeNode.isURI()) { + throw(new InvalidSPDXAnalysisException("Invalid type for licenseInfo - not a URI")); + } + // need to parse the URI + String typeUri = typeNode.getURI(); + if (!typeUri.startsWith(SpdxRdfConstants.SPDX_NAMESPACE)) { + throw(new InvalidSPDXAnalysisException("Invalid type for licenseInfo - not an SPDX type")); + } + String type = typeUri.substring(SpdxRdfConstants.SPDX_NAMESPACE.length()); + if (type.equals(SpdxRdfConstants.CLASS_SPDX_CONJUNCTIVE_LICENSE_SET)) { + return new SPDXConjunctiveLicenseSet(model, node); + } else if (type.equals(SpdxRdfConstants.CLASS_SPDX_DISJUNCTIVE_LICENSE_SET)) { + return new SPDXDisjunctiveLicenseSet(model, node); + }else if (type.equals(SpdxRdfConstants.CLASS_SPDX_EXTRACTED_LICENSING_INFO)) { + return new SPDXNonStandardLicense(model, node); + }else if (type.equals(SpdxRdfConstants.CLASS_SPDX_STANDARD_LICENSE)) { + return new SPDXStandardLicense(model, node); + } else { + throw(new InvalidSPDXAnalysisException("Invalid type for licenseInfo '"+type+"'")); + } + } else { + return null; + } + } + + /** + * Parses a license string and converts it into a SPDXLicenseInfo object + * Syntax - A license set must start and end with a parenthesis "(" + * A conjunctive license set will have and AND after the first + * licenseInfo term + * A disjunctive license set will have an OR after the first + * licenseInfo term + * If there is no And or Or, then it is converted to a simple + * license type (standard or non-standard) + * A space or tab must be used between license ID's and the + * keywords AND and OR + * A licenseID must NOT be "AND" or "OR" + * @param licenseString String conforming to the syntax + * @return an SPDXLicenseInfo created from the string + * @throws InvalidLicenseStringException + */ + public static SPDXLicenseInfo parseSPDXLicenseString(String licenseString) throws InvalidLicenseStringException { + String parseString = licenseString.trim(); + if (parseString.startsWith("(")) { + if (!parseString.endsWith(")")) { + throw(new InvalidLicenseStringException("Missing end ')'")); + } + // this will be treated some form of License Set + parseString = parseString.substring(1, parseString.length()-1).trim(); + return parseLicenseSet(parseString); + } else { + // this is either a standard license or a non-standard license + int startOfIDPos = skipWhiteSpace(parseString, 0); + int endOfIDPos = skipNonWhiteSpace(parseString, startOfIDPos); + String licenseID = parseString.substring(startOfIDPos, endOfIDPos); + if (licenseID.equals(NONE_LICENSE_NAME)) { + return new SPDXNoneLicense(); + } else if (licenseID.equals(NOASSERTION_LICENSE_NAME)) { + return new SpdxNoAssertionLicense(); + } + if (isStandardLicenseID(licenseID)) { + return new SPDXStandardLicense(licenseID, licenseID, null, null, null, null, null, false); + } else { + return new SPDXNonStandardLicense(licenseID, null); + } + } + } + + /** + * Parses a license set which consists of a list of LicenseInfo strings + * @param parseString + * @return + * @throws InvalidLicenseStringException + */ + private static SPDXLicenseInfo parseLicenseSet(String parseString) throws InvalidLicenseStringException { + boolean isConjunctive = false; + boolean isDisjunctive = false; + ArrayList licenseInfoList = new ArrayList(); + int pos = 0; // character position + while (pos < parseString.length()) { + // skip white space + pos = skipWhiteSpace(parseString, pos); + if (pos >= parseString.length()) { + break; // we are done + } + // collect the license information + if (parseString.charAt(pos) == '(') { + int startOfSet = pos + 1; + pos = findEndOfSet(parseString, pos); + if (pos > parseString.length() || parseString.charAt(pos) != ')') { + throw(new InvalidLicenseStringException("Missing end ')'")); + } + licenseInfoList.add(parseLicenseSet(parseString.substring(startOfSet, pos))); + pos++; + } else { + // a license ID + int startOfID = pos; + pos = skipNonWhiteSpace(parseString, pos); + String licenseID = parseString.substring(startOfID, pos); + if (licenseID.equals(NONE_LICENSE_NAME)) { + licenseInfoList.add(new SPDXNoneLicense()); + } else if (licenseID.equals(NOASSERTION_LICENSE_NAME)) { + licenseInfoList.add(new SpdxNoAssertionLicense()); + } + if (isStandardLicenseID(licenseID)) { + licenseInfoList.add(new SPDXStandardLicense(null, licenseID, null, null, null, null, null, false)); + } else { + licenseInfoList.add(new SPDXNonStandardLicense(licenseID, null)); + } + } + if (pos >= parseString.length()) { + break; // done + } + // consume the AND or the OR + // skip more whitespace + pos = skipWhiteSpace(parseString, pos); + if (parseString.charAt(pos) == 'A' || parseString.charAt(pos) == 'a') { + // And + if (pos + 4 >= parseString.length() || + !parseString.substring(pos, pos+4).toUpperCase().equals("AND ")) { + throw(new InvalidLicenseStringException("Expecting an AND")); + } + isConjunctive = true; + pos = pos + 4; + } else if (parseString.charAt(pos) == 'O' || parseString.charAt(pos) == 'o') { + // or + if (pos + 3 >= parseString.length() || + !parseString.substring(pos, pos+3).toUpperCase().equals("OR ")) { + throw(new InvalidLicenseStringException("Expecting an OR")); + } + isDisjunctive = true; + pos = pos + 3; + } else { + throw(new InvalidLicenseStringException("Expecting an AND or an OR")); + } + } + if (isConjunctive && isDisjunctive) { + throw(new InvalidLicenseStringException("Can not have both AND's and OR's inside the same set of parenthesis")); + } + SPDXLicenseInfo[] licenseInfos = new SPDXLicenseInfo[licenseInfoList.size()]; + licenseInfos = licenseInfoList.toArray(licenseInfos); + if (isConjunctive) { + return new SPDXConjunctiveLicenseSet(licenseInfos); + } else if (isDisjunctive) { + return new SPDXDisjunctiveLicenseSet(licenseInfos); + } else { + throw(new InvalidLicenseStringException("Missing AND or OR inside parenthesis")); + } + } + + /** + * @param parseString + * @return + * @throws InvalidLicenseStringException + */ + private static int findEndOfSet(String parseString, int pos) throws InvalidLicenseStringException { + if (parseString.charAt(pos) != '(') { + throw(new InvalidLicenseStringException("Expecting '('")); + } + int retval = pos; + retval++; + while (retval < parseString.length() && parseString.charAt(retval) != ')') { + if (parseString.charAt(retval) == '(') { + retval = findEndOfSet(parseString, retval) + 1; + } else { + retval++; + } + } + return retval; + } + + /** + * @param parseString + * @param pos + * @return + */ + private static int skipWhiteSpace(String parseString, int pos) { + int retval = pos; + char c = parseString.charAt(retval); + while (retval < parseString.length() && + (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { + retval++; + if (retval < parseString.length()) { + c = parseString.charAt(retval); + } + } + return retval; + } + + /** + * @param parseString + * @param pos + * @return + */ + private static int skipNonWhiteSpace(String parseString, int pos) { + int retval = pos; + char c = parseString.charAt(retval); + while (retval < parseString.length() && + c != ' ' && c != '\t' && c != '\r' && c != '\n') { + retval++; + if (retval < parseString.length()) { + c = parseString.charAt(retval); + } + } + return retval; + } + + /** + * @param licenseID + * @return true if the licenseID belongs to a standard license + * @throws InvalidSPDXAnalysisException + */ + public static boolean isStandardLicenseID(String licenseID) { + return STANDARD_LICENSE_ID_SET.contains(licenseID); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseSet.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseSet.java new file mode 100644 index 000000000..93e49cb2b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXLicenseSet.java @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +import com.google.common.collect.Sets; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * A specific form of license information where there is a set of licenses + * represented + * @author Gary O'Neall + * + */ +public abstract class SPDXLicenseSet extends SPDXLicenseInfo { + + protected Set licenseInfos = Sets.newHashSet(); + + /** + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + public SPDXLicenseSet(Model model, Node licenseInfoNode) throws InvalidSPDXAnalysisException { + super(model, licenseInfoNode); + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_SET_MEMEBER).asNode(); + Triple m = Triple.createMatch(licenseInfoNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.licenseInfos.add(SPDXLicenseInfoFactory.getLicenseInfoFromModel(model, t.getObject())); + } + } + + + public SPDXLicenseSet(SPDXLicenseInfo[] licenseInfos) { + super(); + if (licenseInfos != null) { + for (int i = 0; i < licenseInfos.length; i++) { + this.licenseInfos.add(licenseInfos[i]); + } + } + } + + + protected Resource _createResource(Model model, Resource type) { + Resource r = model.createResource(type); + Property licProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_SET_MEMEBER); + Iterator iter = this.licenseInfos.iterator(); + while (iter.hasNext()) { + Resource licResource = iter.next().createResource(model); + r.addProperty(licProperty, licResource); + } + return r; + } + + public void setSPDXLicenseInfos(SPDXLicenseInfo[] licenseInfos) { + this.licenseInfos.clear(); + if (licenseInfos != null) { + for (int i = 0; i < licenseInfos.length; i++) { + this.licenseInfos.add(licenseInfos[i]); + } + } + if (model != null && licenseInfoNode != null) { + // delete any previous created + Property licProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_SET_MEMEBER); + model.removeAll(resource, licProperty, null); + + licProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_LICENSE_SET_MEMEBER); + for (int i = 0; i < licenseInfos.length; i++) { + Resource licResource = licenseInfos[i].createResource(model); + resource.addProperty(licProperty, licResource); + } + } + } + + public SPDXLicenseInfo[] getSPDXLicenseInfos() { + SPDXLicenseInfo[] retval = new SPDXLicenseInfo[this.licenseInfos.size()]; + retval = this.licenseInfos.toArray(retval); + return retval; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#verify() + */ + @Override + public ArrayList verify() { + ArrayList retval = new ArrayList(); + Iterator iter = licenseInfos.iterator(); + while (iter.hasNext()) { + retval.addAll(iter.next().verify()); + } + return retval; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNonStandardLicense.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNonStandardLicense.java new file mode 100644 index 000000000..0240771f8 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNonStandardLicense.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; +import java.util.regex.Pattern; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * A non-standard license which is valid only within an SPDXAnalysis + * @author Gary O'Neall + * + */ +public class SPDXNonStandardLicense extends SPDXLicense { + + static final Pattern NON_STANDARD_LICENSE_PATTERN = Pattern.compile("[-+_.a-zA-Z0-9]{3,}"); + + /** + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + public SPDXNonStandardLicense(Model model, Node licenseInfoNode) throws InvalidSPDXAnalysisException { + super(model, licenseInfoNode); + } + + public SPDXNonStandardLicense(String id, String text) { + super(id, text); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + SpdxRdfConstants.CLASS_SPDX_EXTRACTED_LICENSING_INFO); + return super._createResource(model, type); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#toString() + */ + @Override + public String toString() { + // must be only the ID if we are to use this to create + // parseable license strings + return this.id; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXNonStandardLicense)) { + // covers o == null, as null is not an instance of anything + return false; + } + SPDXNonStandardLicense comp = (SPDXNonStandardLicense)o; + if (this.id == null) { + return (comp.getId() == null); + } else { + return (this.id.equals(comp.getId())); + } + } + + /** + * @return + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String id = this.getId(); + if (id == null || id.isEmpty()) { + retval.add("Missing required license ID"); + } else if (!NON_STANDARD_LICENSE_PATTERN.matcher(id).matches()) { + retval.add("Invalid license id '"+id+"'. Must be at least 3 characters long " + + "and made up of the characters from the set 'a'-'z', 'A'-'Z', '0'-'9', '+', '_', '.', and '-'."); + } + String licenseText = this.getText(); + if (licenseText == null || licenseText.isEmpty()) { + retval.add("Missing required license text"); + } + return retval; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNoneLicense.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNoneLicense.java new file mode 100644 index 000000000..93188b4ef --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXNoneLicense.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * A special license meaning that no license was found + * @author Gary O'Neall + * + */ +public class SPDXNoneLicense extends SPDXLicenseInfo { + + /** + * @param model + * @param node + * @throws InvalidSPDXAnalysisException + */ + public SPDXNoneLicense(Model model, Node node) throws InvalidSPDXAnalysisException { + super(model, node); + } + + public SPDXNoneLicense() { + super(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + return model.createResource(SpdxRdfConstants.SPDX_NAMESPACE+SpdxRdfConstants.TERM_LICENSE_NONE); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#toString() + */ + @Override + public String toString() { + return SPDXLicenseInfoFactory.NONE_LICENSE_NAME; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (o instanceof SPDXNoneLicense) { + // All Instances of this type are considered equal + return true; + } else { + // covers o == null, as null is not an instance of anything + return false; + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#verify() + */ + @Override + public ArrayList verify() { + return new ArrayList(); + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXPackageInfo.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXPackageInfo.java new file mode 100644 index 000000000..59c795985 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXPackageInfo.java @@ -0,0 +1,310 @@ +/** + * Copyright (c) 2011 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.rdfparser; + + +/** + * @author Gary O'Neall + * + */ +public class SPDXPackageInfo { + private String declaredName; + private String fileName; + private String sha1; + private String sourceInfo; + private SPDXLicenseInfo declaredLicenses; + private SPDXLicenseInfo concludedLicense; + private SPDXLicenseInfo[] licensesFromFiles; + private String declaredCopyright; + private String shortDescription; + private String description; + private String url; + private String licenseComments; + private SpdxPackageVerificationCode verificationCode; + private String versionInfo; + private String supplier; + private String originator; + + /** + * @return the verificationCode + */ + public SpdxPackageVerificationCode getVerificationCode() { + return verificationCode; + } + + /** + * @param verificationCode the verificationCode to set + */ + public void setVerificationCode(SpdxPackageVerificationCode verificationCode) { + this.verificationCode = verificationCode; + } + + /** + * @return the versionInfo + */ + public String getVersionInfo() { + return versionInfo; + } + + /** + * @param versionInfo the versionInfo to set + */ + public void setVersionInfo(String versionInfo) { + this.versionInfo = versionInfo; + } + + /** + * @param concludedLicense the concludedLicense to set + */ + public void setConcludedLicense(SPDXLicenseInfo concludedLicense) { + this.concludedLicense = concludedLicense; + } + + public SPDXPackageInfo(String declaredName, String versionInfo, String machineName, + String sha1, String sourceInfo, SPDXLicenseInfo declaredLicense, + SPDXLicenseInfo concludedLicense, SPDXLicenseInfo[] licensesFromFiles, + String licenseComments, String declaredCopyright, String shortDescription, + String description, String url, SpdxPackageVerificationCode spdxPackageVerificationCode, + String supplier, String originator) { + this.declaredName = declaredName; + this.fileName = machineName; + this.sha1 = sha1; + this.sourceInfo = sourceInfo; + this.declaredLicenses = declaredLicense; + this.concludedLicense = concludedLicense; + this.licensesFromFiles = licensesFromFiles; + this.licenseComments = licenseComments; + this.declaredCopyright = declaredCopyright; + this.shortDescription = shortDescription; + this.description = description; + this.url = url; + this.verificationCode = spdxPackageVerificationCode; + this.versionInfo = versionInfo; + this.supplier = supplier; + this.originator = originator; + } + + /** + * @return the supplier + */ + public String getSupplier() { + return supplier; + } + + /** + * @param supplier the supplier to set + */ + public void setSupplier(String supplier) { + this.supplier = supplier; + } + + /** + * @return the originator + */ + public String getOriginator() { + return originator; + } + + /** + * @param originator the originator to set + */ + public void setOriginator(String originator) { + this.originator = originator; + } + + /** + * @return the licensesFromFiles + */ + public SPDXLicenseInfo[] getLicensesFromFiles() { + return licensesFromFiles; + } + + /** + * @param licensesFromFiles the licensesFromFiles to set + */ + public void setLicensesFromFiles(SPDXLicenseInfo[] licensesFromFiles) { + this.licensesFromFiles = licensesFromFiles; + } + + /** + * @return the licenseComments + */ + public String getLicenseComments() { + return licenseComments; + } + + /** + * @param licenseComments the licenseComments to set + */ + public void setLicenseComments(String licenseComments) { + this.licenseComments = licenseComments; + } + + /** + * @return the url + */ + public String getUrl() { + return url; + } + + /** + * @param url the url to set + */ + public void setUrl(String url) { + this.url = url; + } + + /** + * @return the verificationCode + */ + public SpdxPackageVerificationCode getPackageVerification() { + return verificationCode; + } + + /** + * @param verificationCode the verificationCode to set + */ + public void setPackageVerification(SpdxPackageVerificationCode verificationCode) { + this.verificationCode = verificationCode; + } + + /** + * @return the declaredName + */ + public String getDeclaredName() { + return declaredName; + } + + /** + * @param declaredName the declaredName to set + */ + public void setDeclaredName(String declaredName) { + this.declaredName = declaredName; + } + + /** + * @return the fileName + */ + public String getFileName() { + return fileName; + } + + /** + * @param fileName the fileName to set + */ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /** + * @return the sha1 + */ + public String getSha1() { + return sha1; + } + + /** + * @param sha1 the sha1 to set + */ + public void setSha1(String sha1) { + this.sha1 = sha1; + } + + /** + * @return the sourceInfo + */ + public String getSourceInfo() { + return sourceInfo; + } + + /** + * @param sourceInfo the sourceInfo to set + */ + public void setSourceInfo(String sourceInfo) { + this.sourceInfo = sourceInfo; + } + + /** + * @return the declaredLicenses + */ + public SPDXLicenseInfo getDeclaredLicenses() { + return declaredLicenses; + } + + /** + * @param declaredLicenses the declaredLicenses to set + */ + public void setDeclaredLicenses(SPDXLicenseInfo declaredLicenses) { + this.declaredLicenses = declaredLicenses; + } + + /** + * @return the detectedLicenses + */ + public SPDXLicenseInfo getConcludedLicense() { + return concludedLicense; + } + + /** + * @param concludedLicense the detectedLicenses to set + */ + public void setDConcludedLicense(SPDXLicenseInfo concludedLicense) { + this.concludedLicense = concludedLicense; + } + + /** + * @return the declaredCopyright + */ + public String getDeclaredCopyright() { + return declaredCopyright; + } + + /** + * @param declaredCopyright the declaredCopyright to set + */ + public void setDeclaredCopyright(String declaredCopyright) { + this.declaredCopyright = declaredCopyright; + } + + /** + * @return the shortDescription + */ + public String getShortDescription() { + return shortDescription; + } + + /** + * @param shortDescription the shortDescription to set + */ + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXReview.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXReview.java new file mode 100644 index 000000000..2a2cbe424 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXReview.java @@ -0,0 +1,250 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Reviewer class for SPDX Analysis + * @author Gary O'Neall + * + */ +public class SPDXReview { + private String reviewer = null; + private String reviewDate = null; + private String comment = null; + private Model model = null; + private Node reviewerNode = null; + private Resource reviewerResource = null; + + public SPDXReview(Model model, Node reviewerNode) throws InvalidSPDXAnalysisException { + this.model = model; + this.reviewerNode = reviewerNode; + if (reviewerNode.isBlank()) { + reviewerResource = model.createResource(reviewerNode.getBlankNodeId()); + } else if (reviewerNode.isURI()) { + reviewerResource = model.createResource(reviewerNode.getURI()); + } else { + throw(new InvalidSPDXAnalysisException("Can no have a Review node as a literal")); + } + + //reviewer + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_REVIEWER).asNode(); + Triple m = Triple.createMatch(reviewerNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.reviewer = t.getObject().toString(false); + } + //Date + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_DATE).asNode(); + m = Triple.createMatch(reviewerNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.reviewDate = t.getObject().toString(false); + } + //Comment + p = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT).asNode(); + m = Triple.createMatch(reviewerNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.comment = t.getObject().toString(false); + } + } + + /** + * @param reviewer + * @param date + * @param comment + */ + public SPDXReview(String reviewer, String date, String comment) { + this.reviewer = reviewer; + this.reviewDate = date; + this.comment = comment; + } + + public Resource createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + SpdxRdfConstants.CLASS_SPDX_REVIEW); + Resource retval = model.createResource(type); + populateModel(model, retval); + return retval; + } + + /** + * @param model Jena model to populate + * @param projectResource Project resource to populate + */ + private void populateModel(Model model, Resource reviewResource) { + this.model = model; + this.reviewerNode = reviewResource.asNode(); + this.reviewerResource = reviewResource; + + // Reviewer + if (reviewer != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_REVIEWER); + reviewResource.addProperty(p, reviewer); + } + + // Date + if (reviewDate != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_DATE); + reviewResource.addProperty(p, reviewDate); + } + + // Comment + if (comment != null) { + Property p = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + reviewResource.addProperty(p, comment); + } + } + + /** + * @return the reviewer + */ + public String getReviewer() { + return reviewer; + } + + /** + * @param reviewer the reviewer to set + */ + public void setReviewer(String reviewer) { + this.reviewer = reviewer; + if (this.reviewerNode != null && this.model != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_REVIEWER); + model.removeAll(this.reviewerResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_REVIEWER); + this.reviewerResource.addProperty(p, reviewer); + } + } + + /** + * @return the reviewDate + */ + public String getReviewDate() { + return reviewDate; + } + + /** + * @param reviewDate the reviewDate to set + */ + public void setReviewDate(String reviewDate) { + this.reviewDate = reviewDate; + if (this.reviewerNode != null && this.model != null) { + Property p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_DATE); + model.removeAll(this.reviewerResource, p, null); + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_REVIEW_DATE); + this.reviewerResource.addProperty(p, reviewDate); + } + } + + /** + * @return the comment + */ + public String getComment() { + return comment; + } + + /** + * @param comment the comment to set + */ + public void setComment(String comment) { + this.comment = comment; + if (this.reviewerNode != null && this.model != null) { + Property p = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + model.removeAll(this.reviewerResource, p, null); + if (comment != null) { + p = model.createProperty(SpdxRdfConstants.RDFS_NAMESPACE, SpdxRdfConstants.RDFS_PROP_COMMENT); + this.reviewerResource.addProperty(p, comment); + } + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXReview)) { + return false; + } + SPDXReview comp = (SPDXReview)o; + if (this.getReviewer() == null) { + if (comp.getReviewer() != null) { + return false; + } + } else { + if (comp.getReviewer() == null || !this.getReviewer().equals(comp.getReviewer())) { + return false; + } + } + if (this.getComment() == null) { + if (comp.getComment() != null) { + return false; + } + } else { + if (comp.getComment() == null || !this.getComment().equals(comp.getComment())) { + return false; + } + } + if (this.getReviewDate() == null) { + if (comp.getReviewDate() != null) { + return false; + } + } else { + if (comp.getReviewDate() == null || !this.getReviewDate().equals(comp.getReviewDate())) { + return false; + } + } + return true; + } + + /** + * @return + */ + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String reviewer = this.getReviewer(); + if (reviewer == null || reviewer.isEmpty()) { + retval.add("Missing required reviewer"); + } else { + String verify = SpdxVerificationHelper.verifyReviewer(reviewer); + if (verify != null) { + retval.add(verify); + } + } + String reviewDate = this.getReviewDate(); + if (reviewDate == null || reviewDate.isEmpty()) { + retval.add("Missing required review date"); + } else { + String verify = SpdxVerificationHelper.verifyDate(reviewDate); + if (verify != null) { + retval.add(verify); + } + } + @SuppressWarnings("unused") + String reviewerComment = this.getComment(); + // anything to verify for comment? + return retval; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXStandardLicense.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXStandardLicense.java new file mode 100644 index 000000000..01d6535b6 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SPDXStandardLicense.java @@ -0,0 +1,262 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * @author Source Auditor + * + */ +public class SPDXStandardLicense extends SPDXLicense { + + private String name; + private String sourceUrl; + private String notes; + private String standardLicenseHeader; + private String template; + private boolean osiApproved; + + public SPDXStandardLicense(String name, String id, String text, String sourceUrl, String notes, + String standardLicenseHeader, String template, boolean osiApproved) { + super(id, text); + this.name = name; + this.sourceUrl = sourceUrl; + this.notes = notes; + this.standardLicenseHeader = standardLicenseHeader; + this.template = template; + this.osiApproved = osiApproved; + } + /** + * Constructs an SPDX License from the licenseNode + * @param licenseNode RDF graph node representing the SPDX License + * @throws InvalidSPDXAnalysisException + */ + public SPDXStandardLicense(Model spdxModel, Node licenseNode) throws InvalidSPDXAnalysisException { + super(spdxModel, licenseNode); + // name + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_NAME).asNode(); + Triple m = Triple.createMatch(licenseNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.name = t.getObject().toString(false); + } else { + this.name = id; + } + // SourceUrl + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_URL).asNode(); + m = Triple.createMatch(licenseNode, p, null); + tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.sourceUrl = t.getObject().toString(false); + } else { + this.sourceUrl = ""; + } + // notes + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_NOTES).asNode(); + m = Triple.createMatch(licenseNode, p, null); + tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.notes = t.getObject().toString(false); + } else { + this.notes = ""; + } + // standardLicenseHeader + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_HEADER).asNode(); + m = Triple.createMatch(licenseNode, p, null); + tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.standardLicenseHeader = t.getObject().toString(false); + } else { + this.standardLicenseHeader = ""; + } + // template + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_TEMPLATE).asNode(); + m = Triple.createMatch(licenseNode, p, null); + tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.template = t.getObject().toString(false); + } else { + this.template = ""; + } + // OSI Approved + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_STD_LICENSE_OSI_APPROVED).asNode(); + m = Triple.createMatch(licenseNode, p, null); + tripleIter = model.getGraph().find(m); + if (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + if (t.getObject().toString(false).toUpperCase().startsWith("T")) { + this.osiApproved = true; + } else { + this.osiApproved = false; + } + } else { + this.osiApproved = false; + } + } + + /** + * @return the name + */ + public String getName() { + return name; + } + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + /** + * @return the sourceUrl + */ + public String getSourceUrl() { + return sourceUrl; + } + /** + * @param sourceUrl the sourceUrl to set + */ + public void setSourceUrl(String sourceUrl) { + this.sourceUrl = sourceUrl; + } + /** + * @return the notes + */ + public String getNotes() { + return notes; + } + /** + * @param notes the notes to set + */ + public void setNotes(String notes) { + this.notes = notes; + } + /** + * @return the standardLicenseHeader + */ + public String getStandardLicenseHeader() { + return standardLicenseHeader; + } + /** + * @param standardLicenseHeader the standardLicenseHeader to set + */ + public void setStandardLicenseHeader(String standardLicenseHeader) { + this.standardLicenseHeader = standardLicenseHeader; + } + /** + * @return the template + */ + public String getTemplate() { + return template; + } + /** + * @param template the template to set + */ + public void setTemplate(String template) { + this.template = template; + } + + @Override + public String toString() { + // must be only the ID if we want to reuse the + // toString for creating parseable license info strings + return this.id; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE+SpdxRdfConstants.CLASS_SPDX_STANDARD_LICENSE); + String uri = this.createStdLicenseUri(this.id); + Resource r = super._createResource(model, type, uri); + //TODO: Implement additional properties + return r; + } + + /** + * Creates a standard license URI by appending the standard license ID to the URL hosting the SPDX licenses + * @param id Standard License ID + * @return + */ + private String createStdLicenseUri(String id) { + return SpdxRdfConstants.STANDARD_LICENSE_URL + "/" + id; + } + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof SPDXStandardLicense)) { + // covers o == null, as null is not an instance of anything + return false; + } + SPDXStandardLicense comp = (SPDXStandardLicense)o; + if (this.id == null) { + return (comp.getId() == null); + } else { + return (this.id.equals(comp.getId())); + } + } + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#verify() + */ + @Override + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String id = this.getId(); + if (id == null || id.isEmpty()) { + retval.add("Missing required license ID"); + } + //Todo check to see if the id is a standard license id + String name = this.getName(); + if (name == null || name.isEmpty()) { + retval.add("Missing required license name"); + } + this.getNotes(); + this.getSourceUrl(); + this.getStandardLicenseHeader(); + this.getTemplate(); + String licenseText = this.getText(); + if (licenseText == null || licenseText.isEmpty()) { + retval.add("Missing required license text"); + } + return retval; + } + /** + * @return true if the license is listed as an approved license on the OSI website + */ + public boolean isOsiApproved() { + return this.osiApproved; + } + + public void setOsiApproved(boolean osiApproved) { + this.osiApproved = osiApproved; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxNoAssertionLicense.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxNoAssertionLicense.java new file mode 100644 index 000000000..96c5a40c5 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxNoAssertionLicense.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; + +/** + * Special class of license to represent no asserted license license in the file or packages + * @author Gary O'Neall + * + */ +public class SpdxNoAssertionLicense extends SPDXLicenseInfo { + + /** + * @param model + * @param licenseInfoNode + * @throws InvalidSPDXAnalysisException + */ + public SpdxNoAssertionLicense(Model model, Node licenseInfoNode) + throws InvalidSPDXAnalysisException { + super(model, licenseInfoNode); + } + + /** + * + */ + public SpdxNoAssertionLicense() { + super(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#_createResource(org.apache.jena.rdf.model.Model) + */ + @Override + protected Resource _createResource(Model model) { + return model.createResource(SpdxRdfConstants.SPDX_NAMESPACE+SpdxRdfConstants.TERM_LICENSE_NOASSERTION); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#toString() + */ + @Override + public String toString() { + return SPDXLicenseInfoFactory.NOASSERTION_LICENSE_NAME; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (o instanceof SpdxNoAssertionLicense) { + // All instances of this type are considered equal + return true; + } else { + // covers o == null, as null is not an instance of anything + return false; + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.SPDXLicenseInfo#verify() + */ + @Override + public ArrayList verify() { + return new ArrayList(); + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxPackageVerificationCode.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxPackageVerificationCode.java new file mode 100644 index 000000000..b6ed2caa9 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxPackageVerificationCode.java @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.ArrayList; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.Triple; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Property; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.util.iterator.ExtendedIterator; + +/** + * Contains an SPDX Package Verification Code, currently consisting + * of a value and list of excluded files. + * + * @author Gary O'Neall + * + */ +public class SpdxPackageVerificationCode { + + private String value; + private ArrayList excludedFileNames = new ArrayList(); + private Model model; + private Node verificationCodeNode; + private Resource verificationCodeResource; + + + public SpdxPackageVerificationCode(String value, String[] excludedFileNames) { + this.value = value; + for (int i = 0; i < excludedFileNames.length; i++) { + this.excludedFileNames.add(excludedFileNames[i]); + } + this.model = null; + this.verificationCodeNode = null; + this.verificationCodeResource = null; + } + + public SpdxPackageVerificationCode(Model model, Node verificationCodeNode) throws InvalidSPDXAnalysisException { + this.model = model; + this.verificationCodeNode = verificationCodeNode; + if (verificationCodeNode.isBlank()) { + verificationCodeResource = model.createResource(verificationCodeNode.getBlankNodeId()); + } else if (verificationCodeNode.isURI()) { + verificationCodeResource = model.createResource(verificationCodeNode.getURI()); + } else { + throw(new InvalidSPDXAnalysisException("Verification code node can not be a literal")); + } + // excluded filenames + // Algorithm + Node p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_IGNORED_FILES).asNode(); + Triple m = Triple.createMatch(verificationCodeNode, p, null); + ExtendedIterator tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.excludedFileNames.add(t.getObject().toString(false)); + } + + // value + p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_VALUE).asNode(); + m = Triple.createMatch(verificationCodeNode, p, null); + tripleIter = model.getGraph().find(m); + while (tripleIter.hasNext()) { + Triple t = tripleIter.next(); + this.value = t.getObject().toString(false); + } + } + + /** + * Creates a resource from this SPDX Verification Code + * @param model + * @return + */ + public Resource createResource(Model model) { + this.model = model; + Resource type = model.createResource(SpdxRdfConstants.SPDX_NAMESPACE + + SpdxRdfConstants.CLASS_SPDX_VERIFICATIONCODE); + Resource r = model.createResource(type); + if (this.excludedFileNames.size() > 0) { + Property excludedFileProp = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, + SpdxRdfConstants.PROP_VERIFICATIONCODE_IGNORED_FILES); + for (int i = 0; i < this.excludedFileNames.size(); i++) { + r.addProperty(excludedFileProp, this.excludedFileNames.get(i)); + } + } + if (this.value != null && !this.value.isEmpty()) { + Property valueProperty = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_VALUE); + r.addProperty(valueProperty, this.value); + } + this.verificationCodeNode = r.asNode(); + this.verificationCodeResource = r; + return r; + } + + public String[] getExcludedFileNames() { + String[] retval = this.excludedFileNames.toArray(new String[excludedFileNames.size()]); + return retval; + } + + public void setExcludedFileNames(String[] excludedFileNames) { + this.excludedFileNames.clear(); + if (this.verificationCodeNode != null && this.model != null) { + // clear old list + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_IGNORED_FILES); + model.removeAll(this.verificationCodeResource, p, null); + } + for (int i = 0; i < excludedFileNames.length; i++) { + addExcludedFileName(excludedFileNames[i]); + } + } + + public void addExcludedFileName(String excludedFileName) { + this.excludedFileNames.add(excludedFileName); + if (this.verificationCodeNode != null && this.model != null) { + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_IGNORED_FILES); + this.verificationCodeResource.addProperty(p, excludedFileName); + } + } + + public String getValue() { + return this.value; + } + + /** + * @param value the value to set + */ + public void setValue(String value) { + this.value = value; + if (this.model != null && this.verificationCodeNode != null) { + // delete any previous value + Property p = model.getProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_VALUE); + model.removeAll(verificationCodeResource, p, null); + // add the property + p = model.createProperty(SpdxRdfConstants.SPDX_NAMESPACE, SpdxRdfConstants.PROP_VERIFICATIONCODE_VALUE); + verificationCodeResource.addProperty(p, value); + } + } + + public ArrayList verify() { + ArrayList retval = new ArrayList(); + String value = this.getValue(); + if (value == null || value.isEmpty()) { + retval.add("Missing required verification code value"); + } else { + String verify = SpdxVerificationHelper.verifyChecksumString(value); + if (verify != null) { + retval.add(verify); + } + } + return retval; + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxRdfConstants.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxRdfConstants.java new file mode 100644 index 000000000..ffafbb84d --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxRdfConstants.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.util.regex.Pattern; + +/** + * @author Source Auditor + * + */ +public interface SpdxRdfConstants { + + // Namespaces + public static final String RDF_NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + public static final String RDFS_NAMESPACE = "http://www.w3.org/2000/01/rdf-schema#"; + public static final String SPDX_NAMESPACE = "http://spdx.org/rdf/terms#"; + public static final String DOAP_NAMESPACE = "http://usefulinc.com/ns/doap#"; + + // RDF Properties + public static final String RDF_PROP_TYPE = "type"; + public static final String RDF_PROP_RESOURCE = "resource"; + + // RDFS Properties + public static final String RDFS_PROP_COMMENT = "comment"; + + // DOAP Class Names + public static final String CLASS_DOAP_PROJECT = "Project"; + + // DOAP Project Property Names + public static final String PROP_PROJECT_NAME = "name"; + public static final String PROP_PROJECT_HOMEPAGE = "homepage"; + + // SPDX Class Names + public static final String CLASS_SPDX_ANALYSIS = "SpdxDocument"; + public static final String CLASS_SPDX_PACKAGE = "Package"; + public static final String CLASS_SPDX_CREATION_INFO = "CreationInfo"; + public static final String CLASS_SPDX_CHECKSUM = "Checksum"; + public static final String CLASS_SPDX_ANY_LICENSE_INFO = "AnyLicenseInfo"; + public static final String CLASS_SPDX_SIMPLE_LICENSE_INFO = "SimpleLicenseInfo"; + public static final String CLASS_SPDX_CONJUNCTIVE_LICENSE_SET = "ConjunctiveLicenseSet"; + public static final String CLASS_SPDX_DISJUNCTIVE_LICENSE_SET = "DisjunctiveLicenseSet"; + public static final String CLASS_SPDX_EXTRACTED_LICENSING_INFO = "ExtractedLicensingInfo"; + public static final String CLASS_SPDX_STANDARD_LICENSE = "License"; + public static final String CLASS_SPDX_FILE = "File"; + public static final String CLASS_SPDX_REVIEW = "Review"; + public static final String CLASS_SPDX_VERIFICATIONCODE = "PackageVerificationCode"; + + // General SPDX Properties + public static final String PROP_VALUE_NONE = "none"; + public static final String URI_VALUE_NONE = SPDX_NAMESPACE + PROP_VALUE_NONE; + public static final String PROP_VALUE_NOASSERTION = "noassertion"; + public static final String URI_VALUE_NOASSERTION = SPDX_NAMESPACE + PROP_VALUE_NOASSERTION; + + // SPDX Document Properties + public static final String PROP_SPDX_REVIEWED_BY = "reviewed"; + public static final String PROP_SPDX_NONSTANDARD_LICENSES = "hasExtractedLicensingInfo"; + public static final String PROP_SPDX_VERSION = "specVersion"; + public static final String PROP_SPDX_CREATION_INFO = "creationInfo"; + public static final String PROP_SPDX_PACKAGE = "describesPackage"; + public static final String PROP_SPDX_FILE = "referencesFile"; + public static final String PROP_SPDX_DATA_LICENSE = "dataLicense"; + + // SPDX CreationInfo Properties + // - use rdfs:comment static final String PROP_CREATION_CREATOR_COMMENT = "comment"; + public static final String PROP_CREATION_CREATOR = "creator"; + public static final String PROP_CREATION_CREATED = "created"; // creation timestamp + + // SPDX Checksum Properties + public static final String PROP_CHECKSUM_ALGORITHM = "algorithm"; + public static final String PROP_CHECKSUM_VALUE = "checksumValue"; + + // SPDX PackageVerificationCode Properties + public static final String PROP_VERIFICATIONCODE_IGNORED_FILES = "packageVerificationCodeExcludedFile"; + public static final String PROP_VERIFICATIONCODE_VALUE = "packageVerificationCodeValue"; + + + // SPDX Package Properties + public static final String PROP_PACKAGE_DECLARED_NAME = "name"; + public static final String PROP_PACKAGE_FILE_NAME = "packageFileName"; + public static final String PROP_PACKAGE_CHECKSUM = "checksum"; + public static final String PROP_PACKAGE_DOWNLOAD_URL = "downloadLocation"; + public static final String PROP_PACKAGE_SOURCE_INFO = "sourceInfo"; + public static final String PROP_PACKAGE_DECLARED_LICENSE = "licenseDeclared"; + public static final String PROP_PACKAGE_CONCLUDED_LICENSE = "licenseConcluded"; + public static final String PROP_PACKAGE_DECLARED_COPYRIGHT = "copyrightText"; + public static final String PROP_PACKAGE_SHORT_DESC = "summary"; + public static final String PROP_PACKAGE_DESCRIPTION = "description"; + public static final String PROP_PACKAGE_FILE = "hasFile"; + public static final String PROP_PACKAGE_VERIFICATION_CODE = "packageVerificationCode"; + public static final String PROP_PACKAGE_LICENSE_INFO_FROM_FILES = "licenseInfoFromFiles"; + public static final String PROP_PACKAGE_LICENSE_COMMENT = "licenseComments"; + public static final String PROP_PACKAGE_VERSION_INFO = "versionInfo"; + public static final String PROP_PACKAGE_ORIGINATOR = "originator"; + public static final String PROP_PACKAGE_SUPPLIER = "supplier"; + + // SPDX License Properties + public static final String PROP_LICENSE_ID = "licenseId"; + public static final String PROP_LICENSE_TEXT = "licenseText"; + public static final String PROP_EXTRACTED_TEXT = "extractedText"; + public static final String PROP_STD_LICENSE_NAME = "licenseName"; //TODO: replace with actual property + public static final String PROP_STD_LICENSE_URL = "licenseSourceUrl"; //TODO: replace with actual property + public static final String PROP_STD_LICENSE_NOTES = "licenseNotes"; //TODO: replace with actual property + public static final String PROP_STD_LICENSE_HEADER = "licenseHeader"; //TODO: replace with actual property + public static final String PROP_STD_LICENSE_TEMPLATE = "licenseTemplate"; //TODO: replace with actual property + public static final String PROP_STD_LICENSE_OSI_APPROVED = "licenseOsiApproved"; //TODO: replace with actual property + public static final String PROP_LICENSE_SET_MEMEBER = "member"; + public static final String TERM_LICENSE_NOASSERTION = PROP_VALUE_NOASSERTION; + public static final String TERM_LICENSE_NONE = PROP_VALUE_NONE; + + // SPDX File Properties + public static final String PROP_FILE_NAME = "fileName"; + public static final String PROP_FILE_TYPE = "fileType"; + public static final String PROP_FILE_LICENSE = "licenseConcluded"; + public static final String PROP_FILE_COPYRIGHT = "copyrightText"; + public static final String PROP_FILE_CHECKSUM = "checksum"; + public static final String PROP_FILE_SEEN_LICENSE = "licenseInfoInFile"; + public static final String PROP_FILE_LIC_COMMENTS = "licenseComments"; + public static final String PROP_FILE_ARTIFACTOF = "artifactOf"; + + // SPDX Review Properties + public static final String PROP_REVIEW_REVIEWER = "reviewer"; + public static final String PROP_REVIEW_DATE = "reviewDate"; + + // Date format + public static final String SPDX_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + public static final String STANDARD_LICENSE_URL = "http://spdx.org/licenses"; + + // license ID format + public static String NON_STD_LICENSE_ID_PRENUM = "LicenseRef-"; + public static Pattern LICENSE_ID_PATTERN = Pattern.compile(NON_STD_LICENSE_ID_PRENUM+"(\\d+)$"); + + public static Pattern SPDX_VERSION_PATTERN = Pattern.compile("^SPDX-(\\d+)\\.(\\d+)$"); + + // Standard value strings + public static String NONE_VALUE = "NONE"; + public static String NOASSERTION_VALUE = "NOASSERTION"; + + // data license ID + public static final String SPDX_DATA_LICENSE_ID = "PDDL-1.0"; +} \ No newline at end of file diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxVerificationHelper.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxVerificationHelper.java new file mode 100644 index 000000000..f91cad9ea --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/SpdxVerificationHelper.java @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.HashSet; + +import com.google.common.collect.Sets; +import org.apache.jena.iri.IRIFactory; + +/** + * Holds static methods used for verify various property valuse + * @author Gary O'Neall + * + */ +public class SpdxVerificationHelper { + + static IRIFactory iriFactory = IRIFactory.semanticWebImplementation(); + + static Set VALID_FILE_TYPES = Sets.newHashSet(); + + static { + VALID_FILE_TYPES.add("SOURCE"); VALID_FILE_TYPES.add("BINARY"); + VALID_FILE_TYPES.add("ARCHIVE"); VALID_FILE_TYPES.add("OTHER"); + } + + static final String[] VALID_CREATOR_PREFIXES = new String[] {"Person:", "Organization:", "Tool:"}; + static final String[] VALID_ORIGINATOR_SUPPLIER_PREFIXES = new String[] {SpdxRdfConstants.NOASSERTION_VALUE, "Person:", "Organization:"}; + + static String verifyChecksumString(String checksum) { + if (checksum.length() != 40) { + return "Invalid number of characters for checksum"; + } + + for (int i = 0; i < checksum.length(); i++) { + char c = checksum.charAt(i); + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + return "Invalid checksum string character at position "+String.valueOf(i); + } + } + return null; // if we got here, all OK + } + + /** + * @param fileType + * @return + */ + public static String verifyFileType(String fileType) { + if (!VALID_FILE_TYPES.contains(fileType)) { + return "Unrecognized file type"; + } else { + return null; + } + } + + /** + * Verifies a creator string value + * @param creator + * @return + */ + public static String verifyCreator(String creator) { + boolean ok = false; + for (int i = 0; i < VALID_CREATOR_PREFIXES.length; i++) { + if (creator.startsWith(VALID_CREATOR_PREFIXES[i])) { + ok = true; + break; + } + } + if (!ok) { + StringBuilder sb = new StringBuilder("Creator does not start with one of "); + sb.append(VALID_CREATOR_PREFIXES[0]); + for (int i = 1; i < VALID_CREATOR_PREFIXES.length; i++) { + sb.append(", "); + sb.append(VALID_CREATOR_PREFIXES[i]); + } + return sb.toString(); + } else { + return null; + } + } + + /** + * Verifies the originator string + * @param originator + * @return + */ + public static String verifyOriginator(String originator) { + return verifyOriginatorOrSupplier(originator); + } + + /** + * Verifies the supplier String + * @param supplier + * @return + */ + public static String verifySupplier(String supplier) { + return verifyOriginatorOrSupplier(supplier); + } + + /** + * Verifies a the originator or supplier + * @param creator + * @return + */ + private static String verifyOriginatorOrSupplier(String originatorOrSupplier) { + boolean ok = false; + for (int i = 0; i < VALID_ORIGINATOR_SUPPLIER_PREFIXES.length; i++) { + if (originatorOrSupplier.startsWith(VALID_ORIGINATOR_SUPPLIER_PREFIXES[i])) { + ok = true; + break; + } + } + if (!ok) { + StringBuilder sb = new StringBuilder("Value must not start with one of "); + sb.append(VALID_ORIGINATOR_SUPPLIER_PREFIXES[0]); + for (int i = 1; i < VALID_ORIGINATOR_SUPPLIER_PREFIXES.length; i++) { + sb.append(", "); + sb.append(VALID_ORIGINATOR_SUPPLIER_PREFIXES[i]); + } + return sb.toString(); + } else { + return null; + } + } + + /** + * @param creationDate + * @return + */ + public static String verifyDate(String creationDate) { + SimpleDateFormat format = new SimpleDateFormat(SpdxRdfConstants.SPDX_DATE_FORMAT); + try { + format.parse(creationDate); + } catch (ParseException e) { + return("Invalid date format: "+e.getMessage()); + } + return null; + } + + /** + * @param reviewer + * @return + */ + public static String verifyReviewer(String reviewer) { + if (!reviewer.startsWith("Person:")) { + return "Reviewer does not start with Person:"; + } else { + return null; + } + } + + /** + * Validates a URI is indeed valid + * @param uri + * @return + */ + public static boolean isValidUri(String uri) { + return !iriFactory.create(uri).hasViolation(false); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGenerator.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGenerator.java new file mode 100644 index 000000000..b1e06d296 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGenerator.java @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.TreeSet; + +/** + * Generates a package verification code from a directory of source code. + * + * A class implementing the IFileChecksumGenerator is supplied as a parameter to the constructor. + * The method getFileChecksum is called for each file in the directory. This can + * be used as a hook to capture all files in the directory and capture the checksum values at + * a file level. + * + * @author Gary O'Neall + * + */ +public class VerificationCodeGenerator { + + private static final String END_OF_LINE_CHAR = "\n"; + private IFileChecksumGenerator fileChecksumGenerator; + + public VerificationCodeGenerator(IFileChecksumGenerator fileChecksumGenerator) { + this.fileChecksumGenerator = fileChecksumGenerator; + } + /** + * Generate the SPDX Package Verification Code from a directory of files included in the archive + * @param sourceDirectory + * @return + * @throws NoSuchAlgorithmException + * @throws IOException + */ + public SpdxPackageVerificationCode generatePackageVerificationCode(File sourceDirectory, File[] skippedFiles) throws NoSuchAlgorithmException, IOException { + // create a sorted list of file paths + TreeSet skippedFilesPath = new TreeSet(); + String rootOfDirectory = sourceDirectory.getAbsolutePath(); + int rootLen = rootOfDirectory.length()+1; + for (int i = 0; i < skippedFiles.length; i++) { + String skippedPath = normalizeFilePath(skippedFiles[i].getAbsolutePath().substring(rootLen)); + skippedFilesPath.add(skippedPath); + } + ArrayList fileNameAndChecksums = new ArrayList(); + collectFileData(rootOfDirectory, sourceDirectory, fileNameAndChecksums, skippedFilesPath); + Collections.sort(fileNameAndChecksums); + MessageDigest verificationCodeDigest = MessageDigest.getInstance("SHA-1"); + for (int i = 0;i < fileNameAndChecksums.size(); i++) { + byte[] hashInput = fileNameAndChecksums.get(i).getBytes(Charset.forName("UTF-8")); + verificationCodeDigest.update(hashInput); + } + String value = convertChecksumToString(verificationCodeDigest.digest()); + String[] skippedFileNames = new String[skippedFilesPath.size()]; + Iterator iter = skippedFilesPath.iterator(); + int i = 0; + while (iter.hasNext()) { + skippedFileNames[i++] = iter.next(); + } + SpdxPackageVerificationCode retval = new SpdxPackageVerificationCode(value, skippedFileNames); + return retval; + } + + /** + * Collect the file level checksums and filenames + * @param prefixForRelative The portion of the filepath which preceeds the relative file path for the archive + * @param sourceDirectory + * @param fileNameAndChecksums + * @throws IOException + */ + private void collectFileData(String prefixForRelative, File sourceDirectory, + ArrayList fileNameAndChecksums, TreeSet skippedFiles) throws IOException { + if (!sourceDirectory.isDirectory()) { + return; + } + File[] filesAndDirs = sourceDirectory.listFiles(); + for (int i = 0; i < filesAndDirs.length; i++) { + if (filesAndDirs[i].isDirectory()) { + collectFileData(prefixForRelative, filesAndDirs[i], fileNameAndChecksums, skippedFiles); + } else { + String filePath = normalizeFilePath(filesAndDirs[i].getAbsolutePath() + .substring(prefixForRelative.length()+1)); + if (!skippedFiles.contains(filePath)) { + String checksumValue = this.fileChecksumGenerator.getFileChecksum(filesAndDirs[i]).toLowerCase(); + fileNameAndChecksums.add(checksumValue+"||"+filePath+END_OF_LINE_CHAR); + } + } + } + } + + /** + * Normalizes a file path per the SPDX spec + * @param nonNormalizedFilePath + * @return + */ + public static String normalizeFilePath(String nonNormalizedFilePath) { + String filePath = nonNormalizedFilePath.replace('\\', '/').trim(); + if (filePath.contains("../")) { + // need to remove these references + String[] filePathParts = filePath.split("/"); + StringBuilder normalizedFilePath = new StringBuilder(); + for (int j = 0; j < filePathParts.length; j++) { + if (filePathParts[j].equals("..")) { + // remove these from the filePath + } else { + if (j > 0) { + normalizedFilePath.append("/"); + } + normalizedFilePath.append(filePathParts[j]); + } + } + filePath = normalizedFilePath.toString(); + } + filePath.replace("./", ""); + filePath = "./" + filePath; + return filePath; + } + /** + * Convert a byte array SHA-1 digest into a 40 character hex string + * @param digest + * @return + */ + private static String convertChecksumToString(byte[] digest) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < digest.length; i++) { + String hex = Integer.toHexString(0xff & digest[i]); + if (hex.length() < 2) { + sb.append("0"); + } + sb.append(hex); + } + return sb.toString(); + } + /** + * @param sourceDirectory + * @param skippedFiles + * @return + * @throws NoSuchAlgorithmException + * @throws IOException + */ + public SpdxPackageVerificationCode generatePackageVerificationCode( + File sourceDirectory) throws NoSuchAlgorithmException, IOException { + return generatePackageVerificationCode(sourceDirectory, new File[0]); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGeneratorTest.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGeneratorTest.java new file mode 100644 index 000000000..6ac4979ef --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/VerificationCodeGeneratorTest.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2011 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.rdfparser; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Source Auditor + * + */ +public class VerificationCodeGeneratorTest { + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** + * Test method for {@link org.spdx.rdfparser.VerificationCodeGenerator#generatePackageVerificationCode(java.io.File, java.io.File[])}. + */ + @Test + public void testGeneratePackageVerificationCodeFileFileArray() { + fail("Not yet implemented"); + } + + /** + * Test method for {@link org.spdx.rdfparser.VerificationCodeGenerator#normalizeFilePath(java.lang.String)}. + */ + @Test + public void testNormalizeFilePath() { + fail("Not yet implemented"); + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/rdfparser/package-info.java b/TestFiles/spdx-parser-source/org/spdx/rdfparser/package-info.java new file mode 100644 index 000000000..3a1c6887b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/rdfparser/package-info.java @@ -0,0 +1,5 @@ +/* + * @package documentation + * Package level comments line 2 + */ +package org.spdx.rdfparser; diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSheet.java new file mode 100644 index 000000000..36e75885e --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSheet.java @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +/** + * Abstract class representing a workbook sheet used in storing structured data + * @author Gary O'Neall + * + */ +public abstract class AbstractSheet { + // Default style for cells + static final String FONT_NAME = "Arial"; + protected static final short FONT_SIZE = (short)10*20; + static final String CHECKBOX_FONT_NAME = "Wingdings 2"; + static final String CHECKBOX = "P"; + protected CellStyle checkboxStyle; + protected CellStyle dateStyle; + + protected Sheet sheet; + protected int lastRowNum; + protected int firstCellNum; + protected int firstRowNum; + /** + * @param workbook + * @param sheetName + */ + public AbstractSheet(Workbook workbook, String sheetName) { + sheet = workbook.getSheet(sheetName); + if (sheet != null) { + firstRowNum = sheet.getFirstRowNum(); + Row firstRow = sheet.getRow(firstRowNum); + if (firstRow == null) { + firstCellNum = 1; + } else { + firstCellNum = firstRow.getFirstCellNum(); + } + findLastRow(); + } else { + firstRowNum = 0; + lastRowNum = 0; + firstCellNum = 0; + } + createStyles(workbook); + } + + /** + * create the styles in the workbook + */ + private void createStyles(Workbook wb) { + // create the styles + this.checkboxStyle = wb.createCellStyle(); + this.checkboxStyle.setAlignment(CellStyle.ALIGN_CENTER); + this.checkboxStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + this.checkboxStyle.setBorderBottom(CellStyle.BORDER_THIN); + this.checkboxStyle.setBorderLeft(CellStyle.BORDER_THIN); + this.checkboxStyle.setBorderRight(CellStyle.BORDER_THIN); + this.checkboxStyle.setBorderTop(CellStyle.BORDER_THIN); + Font checkboxFont = wb.createFont(); + checkboxFont.setFontHeight(FONT_SIZE); + checkboxFont.setFontName(CHECKBOX_FONT_NAME); + this.checkboxStyle.setFont(checkboxFont); + + this.dateStyle = wb.createCellStyle(); + DataFormat df = wb.createDataFormat(); + this.dateStyle.setDataFormat(df.getFormat("m/d/yy h:mm")); + } + + /** + * + */ + private void findLastRow() { + boolean done = false; + lastRowNum = firstRowNum + 1; + try { + while (!done) { + Row row = sheet.getRow(lastRowNum); + if (row == null || row.getCell(firstCellNum) == null || + row.getCell(firstCellNum).getStringCellValue() == null || + row.getCell(firstCellNum).getStringCellValue().isEmpty()) { + lastRowNum--; + done = true; + } else { + lastRowNum++; + } + } + } + catch (Exception ex) { + // we just stop - stop counting rows at the first invalid row + } + } + + /** + * Add a new row to the end of the sheet + * @return new row + */ + protected Row addRow() { + lastRowNum++; + Row row = sheet.createRow(lastRowNum); + return row; + } + + /** + * Clears all data from the worksheet + */ + public void clear() { + for (int i = lastRowNum; i > firstRowNum; i--) { + Row row = sheet.getRow(i); + sheet.removeRow(row); + } + lastRowNum = firstRowNum; + } + + public int getFirstDataRow() { + return this.firstRowNum + 1; + } + + public int getNumDataRows() { + return this.lastRowNum - (this.firstRowNum); + } + + public Sheet getSheet() { + return this.sheet; + } + + public abstract String verify(); + + public static CellStyle createHeaderStyle(Workbook wb) { + CellStyle headerStyle = wb.createCellStyle(); + headerStyle.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index); + headerStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeight(FONT_SIZE); + headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + headerStyle.setFont(headerFont); + headerStyle.setAlignment(CellStyle.ALIGN_CENTER); + return headerStyle; + } + + public static CellStyle createLeftWrapStyle(Workbook wb) { + CellStyle wrapStyle = wb.createCellStyle(); + wrapStyle.setWrapText(true); + wrapStyle.setAlignment(CellStyle.ALIGN_LEFT); + return wrapStyle; + } + + public static CellStyle createCenterStyle(Workbook wb) { + CellStyle centerStyle = wb.createCellStyle(); + centerStyle.setWrapText(false); + centerStyle.setAlignment(CellStyle.ALIGN_CENTER); + return centerStyle; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSpreadsheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSpreadsheet.java new file mode 100644 index 000000000..6a9f02f8a --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/AbstractSpreadsheet.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.slf4j.Logger; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; + +/** + * Abstract class for implementing file based spreadsheets. + * @author Gary OpNeall + * + */ +public abstract class AbstractSpreadsheet { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractSpreadsheet.class.getName()); + + protected File saveFile; + protected Workbook workbook; + + private boolean readonly; + + /** + * @param spreadsheetFile + * @param create + * @throws AnalyzeException + */ + public AbstractSpreadsheet(File spreadsheetFile, boolean create, boolean readonly) throws SpreadsheetException { + this.readonly = readonly; + if (readonly && create) { + throw(new SpreadsheetException("Can not create a readonly spreadsheet")); + } + if (!spreadsheetFile.exists()) { + if (!create) { + throw(new SpreadsheetException("File "+spreadsheetFile.getName()+" does not exist")); + } + try { + create(spreadsheetFile); + } catch (IOException ex) { + logger.error("IO error creating spreadsheet: "+ex.getMessage()); + throw(new SpreadsheetException("I/O error creating spreadsheet")); + } + } + this.saveFile = spreadsheetFile; + InputStream input = null; + try { + input = new FileInputStream(spreadsheetFile); + workbook = WorkbookFactory.create(input); + } catch (FileNotFoundException ex) { + logger.error("Can not open Excel file. File "+ + spreadsheetFile.getName()+" does not exist"); + throw(new SpreadsheetException("Can not open Excel file. File "+ + spreadsheetFile.getName()+" does not exist")); + } catch (InvalidFormatException ex) { + logger.error("Unable to open workbook. Invalid format: "+ex.getMessage()); + throw(new SpreadsheetException("Unable to open workbook. Invalid format")); + } catch (IOException ex) { + logger.error("IO Exception opening excel workbook: "+ex.getMessage()); + throw(new SpreadsheetException("IO Exception opening excel workbook. See log for more detail.")); + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException ex) { + logger.warn("IO Error closing excel file: "+ex.getMessage()); + } + } + } + } + + public abstract void create(File spreadsheetFile) throws IOException, SpreadsheetException; + public abstract void clear(); + public abstract String verifyWorkbook(); + + /** + * Writes the spreadsheet to a file + * @throws IOException + */ + public void writeToFile(File file) throws IOException { + if (readonly) { + return; + } + FileOutputStream out = null; + try { + out = new FileOutputStream(file); + this.workbook.write(out); + } finally { + if (out != null) { + out.close(); + } + } + + } + + /** + * @throws AnalyzeException + * + */ + public void close() throws SpreadsheetException { + try { + writeToFile(this.saveFile); + } catch (IOException ex) { + logger.error("Error writing excel sheet to file: "+ex.getMessage()); + throw(new SpreadsheetException("Error writing excel workbook to file, see log for details.")); + } + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/InvalidLicenseStringException.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/InvalidLicenseStringException.java new file mode 100644 index 000000000..5c98b8084 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/InvalidLicenseStringException.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +/** + * Exceptions related to License Strings stored in the spreadsheet. Typically + * these are parsine exceptions. + * @author gary O'Neall + * + */ +public class InvalidLicenseStringException extends SpreadsheetException { + /** + * + */ + private static final long serialVersionUID = -1688466911486933160L; + public InvalidLicenseStringException(String message) { + super(message); + } + public InvalidLicenseStringException(String message, Throwable inner) { + super(message, inner); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/NonStandardLicensesSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/NonStandardLicensesSheet.java new file mode 100644 index 000000000..9997c64c9 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/NonStandardLicensesSheet.java @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * Sheet containing the text of any non-standard licenses found in an SPDX document + * @author Gary O'Neall + * + */ +public class NonStandardLicensesSheet extends AbstractSheet { + + static final int NUM_COLS = 2; + static final int IDENTIFIER_COL = 0; + static final int EXTRACTED_TEXT_COL = 1; + + static boolean[] REQUIRED = new boolean[] {true, true}; + static final String[] HEADER_TITLES = new String[] {"Identifier", "Extracted Text"}; + static final int[] COLUMN_WIDTHS = new int[] {15, 120}; + static final boolean[] LEFT_WRAP = new boolean[] {false, false}; + static final boolean[] CENTER_NOWRAP = new boolean[] {true, false}; + + + @SuppressWarnings("unused") + private String version; + /** + * @param workbook + * @param sheetName + * @param version + */ + public NonStandardLicensesSheet(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName); + this.version = version; + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for non-standard Licenses does not exist"; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for non-standard Licenses worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying non-standard License work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + + /* + * Create a blank worksheet NOTE: Replaces / deletes existing sheet by the same name + */ + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle centerStyle = AbstractSheet.createCenterStyle(wb); + CellStyle wrapStyle = AbstractSheet.createLeftWrapStyle(wb); + + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + if (LEFT_WRAP[i]) { + sheet.setDefaultColumnStyle(i, wrapStyle); + } else if (CENTER_NOWRAP[i]) { + sheet.setDefaultColumnStyle(i, centerStyle); + } + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void add(String identifier, String extractedText) { + Row row = addRow(); + Cell idCell = row.createCell(IDENTIFIER_COL); + idCell.setCellValue(identifier); + Cell extractedTextCell = row.createCell(EXTRACTED_TEXT_COL); + extractedTextCell.setCellValue(extractedText); + } + + public String getIdentifier(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell idCell = row.getCell(IDENTIFIER_COL); + if (idCell == null) { + return null; + } + return idCell.getStringCellValue(); + } + + public String getExtractedText(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell extractedTextCell = row.getCell(EXTRACTED_TEXT_COL); + if (extractedTextCell == null) { + return null; + } + return extractedTextCell.getStringCellValue(); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/OriginsSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/OriginsSheet.java new file mode 100644 index 000000000..957348ec5 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/OriginsSheet.java @@ -0,0 +1,303 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.util.Date; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * Sheet containing information about the origins of an SPDX document + * @author Gary O'Neall + * + */ +public class OriginsSheet extends AbstractSheet { + + public static final String CURRENT_VERSION = "0.9.3"; + public static final String VERSION_0_9_2 = "0.9.2"; + public static final String VERSION_0_9_1 = "0.9.1"; + public static final String[] SUPPORTED_VERSIONS = new String[] {CURRENT_VERSION,VERSION_0_9_2, VERSION_0_9_1}; + static final int NUM_COLS = 6; + static final int SPREADSHEET_VERSION_COL = 0; + static final int SPDX_VERSION_COL = SPREADSHEET_VERSION_COL + 1; + static final int CREATED_BY_COL = SPDX_VERSION_COL + 1; + static final int CREATED_COL = CREATED_BY_COL + 1; + static final int DATA_LICENSE_COL = CREATED_COL + 1; + static final int AUTHOR_COMMENTS_COL = DATA_LICENSE_COL + 1; + + static final int DATA_ROW_NUM = 1; + + static final boolean[] REQUIRED = new boolean[] {true, true, true, true, + true, true, false, false}; + + static final String[] HEADER_TITLES = new String[] {"Spreadsheet Version", + "SPDX Version", "Creator", "Created", "Data License", "Creator Comment"}; + static final int[] COLUMN_WIDTHS = new int[] {20, 20, 30, 16, 40, 70}; + static final boolean[] LEFT_WRAP = new boolean[] {false, false, true, false, true, true}; + static final boolean[] CENTER_NOWRAP = new boolean[] {true, true, false, true, false, false}; + String version = CURRENT_VERSION; // updated in the verify method + + public OriginsSheet(Workbook workbook, String sheetName) { + super(workbook, sheetName); + } + + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Origins does not exist"; + } + // validate version + version = getDataCellStringValue(SPREADSHEET_VERSION_COL); + if (version == null) { + return "Invalid origins spreadsheet - no spreadsheet version found"; + } + + if (!verifyVersion(version)) { + return "Spreadsheet version "+version+" not supported."; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Origins worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(SPDX_VERSION_COL) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX Origins work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()+" in Origins Spreadsheet"); + } + } else { + if (i == CREATED_COL) { + if (!(cell.getCellType() == Cell.CELL_TYPE_NUMERIC)) { + return "Created column in origin spreadsheet is not of type Date"; + } + } +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle centerStyle = AbstractSheet.createCenterStyle(wb); + CellStyle wrapStyle = AbstractSheet.createLeftWrapStyle(wb); + Sheet sheet = wb.createSheet(sheetName); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + if (LEFT_WRAP[i]) { + sheet.setDefaultColumnStyle(i, wrapStyle); + } else if (CENTER_NOWRAP[i]) { + sheet.setDefaultColumnStyle(i, centerStyle); + } + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + Row dataRow = sheet.createRow(1); + Cell ssVersionCell = dataRow.createCell(SPREADSHEET_VERSION_COL); + ssVersionCell.setCellValue(CURRENT_VERSION); + } + + private Row getDataRow() { + Row dataRow = sheet.getRow(firstRowNum + DATA_ROW_NUM); + if (dataRow == null) { + dataRow = sheet.createRow(firstRowNum + DATA_ROW_NUM); + } + return dataRow; + } + + private Cell getOrCreateDataCell(int colNum) { + Cell cell = getDataRow().getCell(colNum); + if (cell == null) { + cell = getDataRow().createCell(colNum); + } + cell.setCellType(Cell.CELL_TYPE_NUMERIC); +//TODO: add date format cell.setCellStyle(dateStyle); + return cell; + } + + private void setDataCellStringValue(int colNum, String value) { + getOrCreateDataCell(colNum).setCellValue(value); + } + + private void setDataCellDateValue(int colNum, Date value) { + Cell cell = getOrCreateDataCell(colNum); + cell.setCellValue(value); + cell.setCellStyle(dateStyle); + + } + + private Date getDataCellDateValue(int colNum) { + Cell cell = getDataRow().getCell(colNum); + if (cell == null) { + return null; + } else { + return cell.getDateCellValue(); + } + } + + private String getDataCellStringValue(int colNum) { + Cell cell = getDataRow().getCell(colNum); + if (cell == null) { + return null; + } else { + return cell.getStringCellValue(); + } + } + + public void setAuthorComments(String comments) { + setDataCellStringValue(AUTHOR_COMMENTS_COL, comments); + } + + public void setCreatedBy(String createdBy) { + setDataCellStringValue(CREATED_BY_COL, createdBy); + } + + public void setDataLicense(String dataLicense) { + setDataCellStringValue(DATA_LICENSE_COL, dataLicense); + } + + public void setSPDXVersion(String version) { + setDataCellStringValue(SPDX_VERSION_COL, version); + } + + public void setSpreadsheetVersion(String version) { + setDataCellStringValue(SPREADSHEET_VERSION_COL, version); + } + + public String getAuthorComments() { + return getDataCellStringValue(AUTHOR_COMMENTS_COL); + } + + public Date getCreated() { + return getDataCellDateValue(CREATED_COL); + } + + public String getDataLicense() { + return getDataCellStringValue(DATA_LICENSE_COL); + } + + public String getSPDXVersion() { + return getDataCellStringValue(SPDX_VERSION_COL); + } + + public String getSpreadsheetVersion() { + return getDataCellStringValue(SPREADSHEET_VERSION_COL); + } + + public void setCreatedBy(String[] createdBy) { + if (createdBy == null || createdBy.length < 1) { + setDataCellStringValue(CREATED_BY_COL, ""); + int i = firstRowNum + DATA_ROW_NUM + 1; + Row nextRow = sheet.getRow(i); + while (nextRow != null) { + Cell createdByCell = nextRow.getCell(CREATED_BY_COL); + if (createdByCell != null) { + createdByCell.setCellValue(""); + } + i++; + nextRow = sheet.getRow(i); + } + return; + } + setDataCellStringValue(CREATED_BY_COL, createdBy[0]); + for (int i = 1; i < createdBy.length; i++) { + Row row = sheet.getRow(firstRowNum + DATA_ROW_NUM + i); + if (row == null) { + row = sheet.createRow(firstRowNum + DATA_ROW_NUM + i); + } + Cell cell = row.getCell(CREATED_BY_COL); + if (cell == null) { + cell = row.createCell(CREATED_BY_COL); + } + cell.setCellValue(createdBy[i]); + } + } + + public String[] getCreatedBy() { + // first count rows + int numRows = 0; + while (sheet.getRow(firstRowNum + DATA_ROW_NUM + numRows) != null && + sheet.getRow(firstRowNum + DATA_ROW_NUM + numRows).getCell(CREATED_BY_COL) != null && + !sheet.getRow(firstRowNum + DATA_ROW_NUM + numRows).getCell(CREATED_BY_COL).getStringCellValue().isEmpty()) { + numRows ++; + } + String[] retval = new String[numRows]; + for (int i = 0; i < numRows; i++) { + retval[i] = sheet.getRow(firstRowNum + DATA_ROW_NUM + i).getCell(CREATED_BY_COL).getStringCellValue(); + } + return retval; + } + + public void setCreated(Date created) { + setDataCellDateValue(CREATED_COL, created); + } + + /** + * @param versionToCheck + * @return + */ + public static boolean verifyVersion(String versionToCheck) { + boolean supported = false; + String trVersion = versionToCheck.trim(); + for (int i = 0; i < SUPPORTED_VERSIONS.length; i++) { + if (SUPPORTED_VERSIONS[i].equals(trVersion)) { + supported = true; + break; + } + } + return supported; + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheet.java new file mode 100644 index 000000000..6118e4d6b --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheet.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.SPDXLicenseInfo; +import org.spdx.rdfparser.SPDXPackageInfo; + +/** + * Abstract PackageInfoSheet to manage cross-version implementations + * @author Gary O'Neall + * + */ +public abstract class PackageInfoSheet extends AbstractSheet { + + protected String version; + + public PackageInfoSheet(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName); + this.version = version; + } + + public abstract void add(SPDXPackageInfo pkgInfo); + public abstract SPDXPackageInfo getPackageInfo(int rowNum) throws SpreadsheetException; + + public static String licensesToString(SPDXLicenseInfo[] licenses) { + if (licenses == null || licenses.length == 0) { + return ""; + } else if (licenses.length == 1) { + return licenses[0].toString(); + } else { + StringBuilder sb = new StringBuilder(licenses[0].toString()); + for (int i = 1; i < licenses.length; i++) { + sb.append(", "); + sb.append(licenses[i].toString()); + } + return sb.toString(); + } + } + + public static void create(Workbook wb, String sheetName) { + PackageInfoSheetV09d3.create(wb, sheetName); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d2.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d2.java new file mode 100644 index 000000000..4b303a709 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d2.java @@ -0,0 +1,337 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.SPDXLicenseInfo; +import org.spdx.rdfparser.SPDXLicenseInfoFactory; +import org.spdx.rdfparser.SPDXNoneLicense; +import org.spdx.rdfparser.SPDXPackageInfo; +import org.spdx.rdfparser.SpdxPackageVerificationCode; + +/** + * Sheet describing the package information for an SPDX Document + * @author Gary O'Neall + * + */ +public class PackageInfoSheetV09d2 extends PackageInfoSheet { + + int NUM_COLS = 15; + int NAME_COL = 0; + int VERSION_COL = NAME_COL+1; + int MACHINE_NAME_COL = VERSION_COL+1; + int URL_COL = MACHINE_NAME_COL + 1; + int PACKAGE_SHA_COL = URL_COL + 1; + int FILE_VERIFICATION_VALUE_COL = PACKAGE_SHA_COL + 1; + int VERIFICATION_EXCLUDED_FILES_COL = FILE_VERIFICATION_VALUE_COL + 1; + int SOURCE_INFO_COL = VERIFICATION_EXCLUDED_FILES_COL + 1; + int DECLARED_LICENSE_COL = SOURCE_INFO_COL + 1; + int CONCLUDED_LICENSE_COL = DECLARED_LICENSE_COL + 1; + int LICENSE_INFO_IN_FILES_COL = CONCLUDED_LICENSE_COL + 1; + int LICENSE_COMMENT_COL = LICENSE_INFO_IN_FILES_COL + 1; + int DECLARED_COPYRIGHT_COL = LICENSE_COMMENT_COL + 1; + int SHORT_DESC_COL = DECLARED_COPYRIGHT_COL + 1; + int FULL_DESC_COL = SHORT_DESC_COL + 1; + + + static final boolean[] REQUIRED = new boolean[] {true, false, true, true, + true, true, true, false, true, true, true, false, true, false, false}; + static final String[] HEADER_TITLES = new String[] {"Package Name", "Package Version", + "Package FileName", "Package Download Location", "Package Checksum", "Package Verification Code", + "Verification Code Excluded Files", "Source Info", "License Declared", "License Concluded", "License Info From Files", + "License Comments", "Package Copyright Text", "Summary", "Description"}; + + static final int[] COLUMN_WIDTHS = new int[] {30, 17, 30, 50, 25, 25, 40, 30, + 40, 40, 90, 50, 50, 50, 80}; + + /** + * @param workbook + * @param sheetName + * @param version + */ + public PackageInfoSheetV09d2(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName, version); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Package Info does not exist"; + } + if (!OriginsSheet.verifyVersion(version)) { + return "Unsupported version "+version; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Package Info worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX Package Info work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { + if (i == DECLARED_LICENSE_COL || i == CONCLUDED_LICENSE_COL) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue()); + } catch(SpreadsheetException ex) { + if (i == DECLARED_LICENSE_COL) { + return "Invalid declared license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } else { + return "Invalid seen license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } else if (i == LICENSE_INFO_IN_FILES_COL) { + String[] licenses = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + if (licenses.length < 1) { + return "Missing licenss infos in files"; + } + for (int j = 0; j < licenses.length; j++) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue().trim()); + } catch(SpreadsheetException ex) { + return "Invalid license infos in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle defaultStyle = AbstractSheet.createLeftWrapStyle(wb); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + sheet.setDefaultColumnStyle(i, defaultStyle); + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void add(SPDXPackageInfo pkgInfo) { + Row row = addRow(); + Cell nameCell = row.createCell(NAME_COL); + nameCell.setCellValue(pkgInfo.getDeclaredName()); + Cell copyrightCell = row.createCell(DECLARED_COPYRIGHT_COL); + copyrightCell.setCellValue(pkgInfo.getDeclaredCopyright()); + Cell DeclaredLicenseCol = row.createCell(DECLARED_LICENSE_COL); + DeclaredLicenseCol.setCellValue(pkgInfo.getDeclaredLicenses().toString()); + Cell concludedLicenseCol = row.createCell(CONCLUDED_LICENSE_COL); + concludedLicenseCol.setCellValue(pkgInfo.getConcludedLicense().toString()); + Cell fileChecksumCell = row.createCell(FILE_VERIFICATION_VALUE_COL); + if (pkgInfo.getPackageVerification() != null) { + fileChecksumCell.setCellValue(pkgInfo.getPackageVerification().getValue()); + Cell verificationExcludedFilesCell = row.createCell(VERIFICATION_EXCLUDED_FILES_COL); + StringBuilder excFilesStr = new StringBuilder(); + String[] excludedFiles = pkgInfo.getPackageVerification().getExcludedFileNames(); + if (excludedFiles.length > 0) { + excFilesStr.append(excludedFiles[0]); + for (int i = 1;i < excludedFiles.length; i++) { + excFilesStr.append(", "); + excFilesStr.append(excludedFiles[i]); + } + } + verificationExcludedFilesCell.setCellValue(excFilesStr.toString()); + } + + if (pkgInfo.getDescription() != null) { + Cell descCell = row.createCell(FULL_DESC_COL); + descCell.setCellValue(pkgInfo.getDescription()); + } + Cell fileNameCell = row.createCell(MACHINE_NAME_COL); + fileNameCell.setCellValue(pkgInfo.getFileName()); + Cell pkgSha1 = row.createCell(PACKAGE_SHA_COL); + if (pkgInfo.getSha1() != null) { + pkgSha1.setCellValue(pkgInfo.getSha1()); + } + // add the license infos in files in multiple rows + SPDXLicenseInfo[] licenseInfosInFiles = pkgInfo.getLicensesFromFiles(); + if (licenseInfosInFiles != null && licenseInfosInFiles.length > 0) { + StringBuilder sb = new StringBuilder(licenseInfosInFiles[0].toString()); + for (int i = 1; i < licenseInfosInFiles.length; i++) { + sb.append(","); + sb.append(licenseInfosInFiles[i].toString()); + } + row.createCell(LICENSE_INFO_IN_FILES_COL).setCellValue(sb.toString()); + } + if (pkgInfo.getLicenseComments() != null) { + row.createCell(LICENSE_COMMENT_COL).setCellValue(pkgInfo.getLicenseComments()); + } + if (pkgInfo.getShortDescription() != null) { + Cell shortDescCell = row.createCell(SHORT_DESC_COL); + shortDescCell.setCellValue(pkgInfo.getShortDescription()); + } + if (pkgInfo.getSourceInfo() != null) { + Cell sourceInfoCell = row.createCell(SOURCE_INFO_COL); + sourceInfoCell.setCellValue(pkgInfo.getSourceInfo()); + } + Cell urlCell = row.createCell(URL_COL); + urlCell.setCellValue(pkgInfo.getUrl()); + if (pkgInfo.getVersionInfo() != null) { + Cell versionInfoCell = row.createCell(VERSION_COL); + versionInfoCell.setCellValue(pkgInfo.getVersionInfo()); + } + } + + public SPDXPackageInfo getPackageInfo(int rowNum) throws SpreadsheetException { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell nameCell = row.getCell(NAME_COL); + if (nameCell == null || nameCell.getStringCellValue().isEmpty()) { + return null; + } + String error = validateRow(row); + if (error != null && !error.isEmpty()) { + throw(new SpreadsheetException(error)); + } + String declaredName = nameCell.getStringCellValue(); + String machineName = row.getCell(MACHINE_NAME_COL).getStringCellValue(); + String sha1 = row.getCell(PACKAGE_SHA_COL).getStringCellValue(); + String sourceInfo; + Cell sourceInfocol = row.getCell(SOURCE_INFO_COL); + if (sourceInfocol != null) { + sourceInfo = sourceInfocol.getStringCellValue(); + } else { + sourceInfo = ""; + } + SPDXLicenseInfo declaredLicenses = + SPDXLicenseInfoFactory.parseSPDXLicenseString(row.getCell(DECLARED_LICENSE_COL).getStringCellValue()); + SPDXLicenseInfo concludedLicense; + Cell concludedLicensesCell = row.getCell(CONCLUDED_LICENSE_COL); + if (concludedLicensesCell != null && !concludedLicensesCell.getStringCellValue().isEmpty()) { + concludedLicense = SPDXLicenseInfoFactory.parseSPDXLicenseString(concludedLicensesCell.getStringCellValue()); + } else { + concludedLicense = new SPDXNoneLicense(); + } + String[] licenseStrings = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + SPDXLicenseInfo[] licenseInfosFromFiles = new SPDXLicenseInfo[licenseStrings.length]; + for (int i = 0; i < licenseStrings.length; i++) { + licenseInfosFromFiles[i] = SPDXLicenseInfoFactory.parseSPDXLicenseString(licenseStrings[i].trim()); + } + Cell licenseCommentCell = row.getCell(LICENSE_COMMENT_COL); + String licenseComment; + if (licenseCommentCell != null && !licenseCommentCell.getStringCellValue().isEmpty()) { + licenseComment = licenseCommentCell.getStringCellValue(); + } else { + licenseComment = ""; + } + String declaredCopyright = row.getCell(DECLARED_COPYRIGHT_COL).getStringCellValue(); + Cell shortDescCell = row.getCell(SHORT_DESC_COL); + String shortDesc; + if (shortDescCell != null && !shortDescCell.getStringCellValue().isEmpty()) { + shortDesc = shortDescCell.getStringCellValue(); + } else { + shortDesc = ""; + } + Cell descCell = row.getCell(FULL_DESC_COL); + String description; + if (descCell != null && !descCell.getStringCellValue().isEmpty()) { + description = descCell.getStringCellValue(); + } else { + description = ""; + } + String url = row.getCell(URL_COL).getStringCellValue(); + String packageVerificationValue = row.getCell(FILE_VERIFICATION_VALUE_COL).getStringCellValue(); + String[] excludedFiles; + String excludedFilesStr = row.getCell(VERIFICATION_EXCLUDED_FILES_COL).getStringCellValue(); + if (excludedFilesStr != null && !excludedFilesStr.isEmpty()) { + excludedFiles = excludedFilesStr.split(","); + for (int i = 0;i < excludedFiles.length; i++) { + excludedFiles[i] = excludedFiles[i].trim(); + } + } else { + excludedFiles = new String[0]; + } + Cell versionInfoCell = row.getCell(VERSION_COL); + String versionInfo; + if (versionInfoCell != null && !versionInfoCell.getStringCellValue().isEmpty()) { + versionInfo = versionInfoCell.getStringCellValue(); + } else { + versionInfo = ""; + } + SpdxPackageVerificationCode verificationCode = new SpdxPackageVerificationCode(packageVerificationValue, excludedFiles); + return new SPDXPackageInfo(declaredName, versionInfo, machineName, sha1, sourceInfo, + declaredLicenses, concludedLicense, licenseInfosFromFiles, + licenseComment, declaredCopyright, shortDesc, + description, url, verificationCode, "", ""); + } + + public static String licensesToString(SPDXLicenseInfo[] licenses) { + if (licenses == null || licenses.length == 0) { + return ""; + } else if (licenses.length == 1) { + return licenses[0].toString(); + } else { + StringBuilder sb = new StringBuilder(licenses[0].toString()); + for (int i = 1; i < licenses.length; i++) { + sb.append(", "); + sb.append(licenses[i].toString()); + } + return sb.toString(); + } + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d3.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d3.java new file mode 100644 index 000000000..68f3c22ff --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV09d3.java @@ -0,0 +1,384 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.SPDXLicenseInfo; +import org.spdx.rdfparser.SPDXLicenseInfoFactory; +import org.spdx.rdfparser.SPDXNoneLicense; +import org.spdx.rdfparser.SPDXPackageInfo; +import org.spdx.rdfparser.SpdxPackageVerificationCode; +import org.spdx.rdfparser.SpdxVerificationHelper; + +/** + * @author Source Auditor + * + */ +public class PackageInfoSheetV09d3 extends PackageInfoSheet { + + int NUM_COLS = 17; + int NAME_COL = 0; + int VERSION_COL = NAME_COL+1; + int MACHINE_NAME_COL = VERSION_COL+1; + int SUPPLIER_COL = MACHINE_NAME_COL + 1; + int ORIGINATOR_COL = SUPPLIER_COL + 1; + int URL_COL = ORIGINATOR_COL + 1; + int PACKAGE_SHA_COL = URL_COL + 1; + int FILE_VERIFICATION_VALUE_COL = PACKAGE_SHA_COL + 1; + int VERIFICATION_EXCLUDED_FILES_COL = FILE_VERIFICATION_VALUE_COL + 1; + int SOURCE_INFO_COL = VERIFICATION_EXCLUDED_FILES_COL + 1; + int DECLARED_LICENSE_COL = SOURCE_INFO_COL + 1; + int CONCLUDED_LICENSE_COL = DECLARED_LICENSE_COL + 1; + int LICENSE_INFO_IN_FILES_COL = CONCLUDED_LICENSE_COL + 1; + int LICENSE_COMMENT_COL = LICENSE_INFO_IN_FILES_COL + 1; + int DECLARED_COPYRIGHT_COL = LICENSE_COMMENT_COL + 1; + int SHORT_DESC_COL = DECLARED_COPYRIGHT_COL + 1; + int FULL_DESC_COL = SHORT_DESC_COL + 1; + + + static final boolean[] REQUIRED = new boolean[] {true, false, true, false, false, true, + true, true, true, false, true, true, true, false, true, false, false}; + static final String[] HEADER_TITLES = new String[] {"Package Name", "Package Version", + "Package FileName", "Package Supplier", "Package Originator", "Package Download Location", "Package Checksum", "Package Verification Code", + "Verification Code Excluded Files", "Source Info", "License Declared", "License Concluded", "License Info From Files", + "License Comments", "Package Copyright Text", "Summary", "Description"}; + + static final int[] COLUMN_WIDTHS = new int[] {30, 17, 30, 30, 30, 50, 25, 25, 40, 30, + 40, 40, 90, 50, 50, 50, 80}; + + /** + * @param workbook + * @param sheetName + * @param version + */ + public PackageInfoSheetV09d3(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName, version); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Package Info does not exist"; + } + if (!OriginsSheet.verifyVersion(version)) { + return "Unsupported version "+version; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Package Info worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX Package Info work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { + if (i == DECLARED_LICENSE_COL || i == CONCLUDED_LICENSE_COL) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue()); + } catch(SpreadsheetException ex) { + if (i == DECLARED_LICENSE_COL) { + return "Invalid declared license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } else { + return "Invalid seen license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } else if (i == LICENSE_INFO_IN_FILES_COL) { + String[] licenses = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + if (licenses.length < 1) { + return "Missing licenss infos in files"; + } + for (int j = 0; j < licenses.length; j++) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue().trim()); + } catch(SpreadsheetException ex) { + return "Invalid license infos in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } else if (i == ORIGINATOR_COL) { + Cell origCell = row.getCell(ORIGINATOR_COL); + if (origCell != null) { + String originator = origCell.getStringCellValue(); + if (originator != null && !originator.isEmpty()) { + String error = SpdxVerificationHelper.verifyOriginator(originator); + if (error != null && !error.isEmpty()) { + return "Invalid originator in row "+String.valueOf(row.getRowNum()) + ": "+error; + } + } + } + } else if (i == SUPPLIER_COL) { + Cell supplierCell = row.getCell(SUPPLIER_COL); + if (supplierCell != null) { + String supplier = supplierCell.getStringCellValue(); + if (supplier != null && !supplier.isEmpty()) { + String error = SpdxVerificationHelper.verifySupplier(supplier); + if (error != null && !error.isEmpty()) { + return "Invalid supplier in row "+String.valueOf(row.getRowNum()) + ": "+error; + } + } + } + } +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle defaultStyle = AbstractSheet.createLeftWrapStyle(wb); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + sheet.setDefaultColumnStyle(i, defaultStyle); + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void add(SPDXPackageInfo pkgInfo) { + Row row = addRow(); + Cell nameCell = row.createCell(NAME_COL); + nameCell.setCellValue(pkgInfo.getDeclaredName()); + Cell copyrightCell = row.createCell(DECLARED_COPYRIGHT_COL); + copyrightCell.setCellValue(pkgInfo.getDeclaredCopyright()); + Cell DeclaredLicenseCol = row.createCell(DECLARED_LICENSE_COL); + DeclaredLicenseCol.setCellValue(pkgInfo.getDeclaredLicenses().toString()); + Cell concludedLicenseCol = row.createCell(CONCLUDED_LICENSE_COL); + concludedLicenseCol.setCellValue(pkgInfo.getConcludedLicense().toString()); + Cell fileChecksumCell = row.createCell(FILE_VERIFICATION_VALUE_COL); + if (pkgInfo.getPackageVerification() != null) { + fileChecksumCell.setCellValue(pkgInfo.getPackageVerification().getValue()); + Cell verificationExcludedFilesCell = row.createCell(VERIFICATION_EXCLUDED_FILES_COL); + StringBuilder excFilesStr = new StringBuilder(); + String[] excludedFiles = pkgInfo.getPackageVerification().getExcludedFileNames(); + if (excludedFiles.length > 0) { + excFilesStr.append(excludedFiles[0]); + for (int i = 1;i < excludedFiles.length; i++) { + excFilesStr.append(", "); + excFilesStr.append(excludedFiles[i]); + } + } + verificationExcludedFilesCell.setCellValue(excFilesStr.toString()); + } + + if (pkgInfo.getDescription() != null) { + Cell descCell = row.createCell(FULL_DESC_COL); + descCell.setCellValue(pkgInfo.getDescription()); + } + Cell fileNameCell = row.createCell(MACHINE_NAME_COL); + fileNameCell.setCellValue(pkgInfo.getFileName()); + Cell pkgSha1 = row.createCell(PACKAGE_SHA_COL); + if (pkgInfo.getSha1() != null) { + pkgSha1.setCellValue(pkgInfo.getSha1()); + } + // add the license infos in files in multiple rows + SPDXLicenseInfo[] licenseInfosInFiles = pkgInfo.getLicensesFromFiles(); + if (licenseInfosInFiles != null && licenseInfosInFiles.length > 0) { + StringBuilder sb = new StringBuilder(licenseInfosInFiles[0].toString()); + for (int i = 1; i < licenseInfosInFiles.length; i++) { + sb.append(","); + sb.append(licenseInfosInFiles[i].toString()); + } + row.createCell(LICENSE_INFO_IN_FILES_COL).setCellValue(sb.toString()); + } + if (pkgInfo.getLicenseComments() != null) { + row.createCell(LICENSE_COMMENT_COL).setCellValue(pkgInfo.getLicenseComments()); + } + if (pkgInfo.getShortDescription() != null) { + Cell shortDescCell = row.createCell(SHORT_DESC_COL); + shortDescCell.setCellValue(pkgInfo.getShortDescription()); + } + if (pkgInfo.getSourceInfo() != null) { + Cell sourceInfoCell = row.createCell(SOURCE_INFO_COL); + sourceInfoCell.setCellValue(pkgInfo.getSourceInfo()); + } + Cell urlCell = row.createCell(URL_COL); + urlCell.setCellValue(pkgInfo.getUrl()); + if (pkgInfo.getVersionInfo() != null) { + Cell versionInfoCell = row.createCell(VERSION_COL); + versionInfoCell.setCellValue(pkgInfo.getVersionInfo()); + } + if (pkgInfo.getOriginator() != null) { + Cell originatorCell = row.createCell(ORIGINATOR_COL); + originatorCell.setCellValue(pkgInfo.getOriginator()); + } + if (pkgInfo.getSupplier() != null) { + Cell supplierCell = row.createCell(SUPPLIER_COL); + supplierCell.setCellValue(pkgInfo.getSupplier()); + } + } + + public SPDXPackageInfo getPackageInfo(int rowNum) throws SpreadsheetException { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell nameCell = row.getCell(NAME_COL); + if (nameCell == null || nameCell.getStringCellValue().isEmpty()) { + return null; + } + String error = validateRow(row); + if (error != null && !error.isEmpty()) { + throw(new SpreadsheetException(error)); + } + String declaredName = nameCell.getStringCellValue(); + String machineName = row.getCell(MACHINE_NAME_COL).getStringCellValue(); + String sha1 = row.getCell(PACKAGE_SHA_COL).getStringCellValue(); + String sourceInfo; + Cell sourceInfocol = row.getCell(SOURCE_INFO_COL); + if (sourceInfocol != null) { + sourceInfo = sourceInfocol.getStringCellValue(); + } else { + sourceInfo = ""; + } + SPDXLicenseInfo declaredLicenses = + SPDXLicenseInfoFactory.parseSPDXLicenseString(row.getCell(DECLARED_LICENSE_COL).getStringCellValue()); + SPDXLicenseInfo concludedLicense; + Cell concludedLicensesCell = row.getCell(CONCLUDED_LICENSE_COL); + if (concludedLicensesCell != null && !concludedLicensesCell.getStringCellValue().isEmpty()) { + concludedLicense = SPDXLicenseInfoFactory.parseSPDXLicenseString(concludedLicensesCell.getStringCellValue()); + } else { + concludedLicense = new SPDXNoneLicense(); + } + String[] licenseStrings = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + SPDXLicenseInfo[] licenseInfosFromFiles = new SPDXLicenseInfo[licenseStrings.length]; + for (int i = 0; i < licenseStrings.length; i++) { + licenseInfosFromFiles[i] = SPDXLicenseInfoFactory.parseSPDXLicenseString(licenseStrings[i].trim()); + } + Cell licenseCommentCell = row.getCell(LICENSE_COMMENT_COL); + String licenseComment; + if (licenseCommentCell != null && !licenseCommentCell.getStringCellValue().isEmpty()) { + licenseComment = licenseCommentCell.getStringCellValue(); + } else { + licenseComment = ""; + } + String declaredCopyright = row.getCell(DECLARED_COPYRIGHT_COL).getStringCellValue(); + Cell shortDescCell = row.getCell(SHORT_DESC_COL); + String shortDesc; + if (shortDescCell != null && !shortDescCell.getStringCellValue().isEmpty()) { + shortDesc = shortDescCell.getStringCellValue(); + } else { + shortDesc = ""; + } + Cell descCell = row.getCell(FULL_DESC_COL); + String description; + if (descCell != null && !descCell.getStringCellValue().isEmpty()) { + description = descCell.getStringCellValue(); + } else { + description = ""; + } + String url = row.getCell(URL_COL).getStringCellValue(); + String packageVerificationValue = row.getCell(FILE_VERIFICATION_VALUE_COL).getStringCellValue(); + String[] excludedFiles; + String excludedFilesStr = row.getCell(VERIFICATION_EXCLUDED_FILES_COL).getStringCellValue(); + if (excludedFilesStr != null && !excludedFilesStr.isEmpty()) { + excludedFiles = excludedFilesStr.split(","); + for (int i = 0;i < excludedFiles.length; i++) { + excludedFiles[i] = excludedFiles[i].trim(); + } + } else { + excludedFiles = new String[0]; + } + Cell versionInfoCell = row.getCell(VERSION_COL); + String versionInfo; + if (versionInfoCell != null && !versionInfoCell.getStringCellValue().isEmpty()) { + versionInfo = versionInfoCell.getStringCellValue(); + } else { + versionInfo = ""; + } + String supplier; + Cell supplierCell = row.getCell(SUPPLIER_COL); + if (supplierCell != null && !supplierCell.getStringCellValue().isEmpty()) { + supplier = supplierCell.getStringCellValue(); + } else { + supplier = ""; + } + String originator; + Cell originatorCell = row.getCell(ORIGINATOR_COL); + if (originatorCell != null && !originatorCell.getStringCellValue().isEmpty()) { + originator = originatorCell.getStringCellValue(); + } else { + originator = ""; + } + SpdxPackageVerificationCode verificationCode = new SpdxPackageVerificationCode(packageVerificationValue, excludedFiles); + return new SPDXPackageInfo(declaredName, versionInfo, machineName, sha1, sourceInfo, + declaredLicenses, concludedLicense, licenseInfosFromFiles, + licenseComment, declaredCopyright, shortDesc, + description, url, verificationCode, supplier, originator); + } + + public static String licensesToString(SPDXLicenseInfo[] licenses) { + if (licenses == null || licenses.length == 0) { + return ""; + } else if (licenses.length == 1) { + return licenses[0].toString(); + } else { + StringBuilder sb = new StringBuilder(licenses[0].toString()); + for (int i = 1; i < licenses.length; i++) { + sb.append(", "); + sb.append(licenses[i].toString()); + } + return sb.toString(); + } + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV9d1.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV9d1.java new file mode 100644 index 000000000..0bdc2ccdc --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PackageInfoSheetV9d1.java @@ -0,0 +1,307 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.SPDXLicenseInfo; +import org.spdx.rdfparser.SPDXLicenseInfoFactory; +import org.spdx.rdfparser.SPDXNoneLicense; +import org.spdx.rdfparser.SPDXPackageInfo; +import org.spdx.rdfparser.SpdxPackageVerificationCode; + +/** + * Sheet describing the package information for an SPDX Document + * @author Gary O'Neall + * + */ +public class PackageInfoSheetV9d1 extends PackageInfoSheet { + + int NUM_COLS = 14; + int NAME_COL = 0; + int MACHINE_NAME_COL = NAME_COL+1; + int URL_COL = MACHINE_NAME_COL + 1; + int PACKAGE_SHA_COL = URL_COL + 1; + int FILE_VERIFICATION_VALUE_COL = PACKAGE_SHA_COL + 1; + int VERIFICATION_EXCLUDED_FILES_COL = FILE_VERIFICATION_VALUE_COL + 1; + int SOURCE_INFO_COL = VERIFICATION_EXCLUDED_FILES_COL + 1; + int DECLARED_LICENSE_COL = SOURCE_INFO_COL + 1; + int CONCLUDED_LICENSE_COL = DECLARED_LICENSE_COL + 1; + int LICENSE_INFO_IN_FILES_COL = CONCLUDED_LICENSE_COL + 1; + int LICENSE_COMMENT_COL = LICENSE_INFO_IN_FILES_COL + 1; + int DECLARED_COPYRIGHT_COL = LICENSE_COMMENT_COL + 1; + int SHORT_DESC_COL = DECLARED_COPYRIGHT_COL + 1; + int FULL_DESC_COL = SHORT_DESC_COL + 1; + + static final boolean[] REQUIRED = new boolean[] {true, true, true, + true, true, true, false, true, true, true, false, true, false, false}; + static final String[] HEADER_TITLES = new String[] {"Package Name", + "Package FileName", "Package Download Location", "Package Checksum", "Package Verification Code", + "Verification Code Excluded Files", "Source Info", "License Declared", "License Concluded", "License Info From Files", + "License Comments", "Package Copyright Text", "Summary", "Description"}; + + static final int[] COLUMN_WIDTHS = new int[] {30, 30, 50, 25, 25, 40, 30, + 40, 40, 90, 50, 50, 50, 80}; + + /** + * @param workbook + * @param sheetName + * @param version + */ + public PackageInfoSheetV9d1(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName, version); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Package Info does not exist"; + } + if (!OriginsSheet.verifyVersion(version)) { + return "Unsupported version "+version; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Package Info worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX Package Info work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { + if (i == DECLARED_LICENSE_COL || i == CONCLUDED_LICENSE_COL) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue()); + } catch(SpreadsheetException ex) { + if (i == DECLARED_LICENSE_COL) { + return "Invalid declared license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } else { + return "Invalid seen license in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } else if (i == LICENSE_INFO_IN_FILES_COL) { + String[] licenses = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + if (licenses.length < 1) { + return "Missing licenss infos in files"; + } + for (int j = 0; j < licenses.length; j++) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue().trim()); + } catch(SpreadsheetException ex) { + return "Invalid license infos in row "+String.valueOf(row.getRowNum())+" detail: "+ex.getMessage(); + } + } + } +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle defaultStyle = AbstractSheet.createLeftWrapStyle(wb); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + sheet.setDefaultColumnStyle(i, defaultStyle); + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void add(SPDXPackageInfo pkgInfo) { + Row row = addRow(); + Cell nameCell = row.createCell(NAME_COL); + nameCell.setCellValue(pkgInfo.getDeclaredName()); + Cell copyrightCell = row.createCell(DECLARED_COPYRIGHT_COL); + copyrightCell.setCellValue(pkgInfo.getDeclaredCopyright()); + Cell DeclaredLicenseCol = row.createCell(DECLARED_LICENSE_COL); + DeclaredLicenseCol.setCellValue(pkgInfo.getDeclaredLicenses().toString()); + Cell concludedLicenseCol = row.createCell(CONCLUDED_LICENSE_COL); + concludedLicenseCol.setCellValue(pkgInfo.getConcludedLicense().toString()); + Cell fileChecksumCell = row.createCell(FILE_VERIFICATION_VALUE_COL); + fileChecksumCell.setCellValue(pkgInfo.getPackageVerification().getValue()); + Cell verificationExcludedFilesCell = row.createCell(VERIFICATION_EXCLUDED_FILES_COL); + StringBuilder excFilesStr = new StringBuilder(); + String[] excludedFiles = pkgInfo.getPackageVerification().getExcludedFileNames(); + if (excludedFiles.length > 0) { + excFilesStr.append(excludedFiles[0]); + for (int i = 1;i < excludedFiles.length; i++) { + excFilesStr.append(", "); + excFilesStr.append(excludedFiles[i]); + } + } + verificationExcludedFilesCell.setCellValue(excFilesStr.toString()); + if (pkgInfo.getDescription() != null) { + Cell descCell = row.createCell(FULL_DESC_COL); + descCell.setCellValue(pkgInfo.getDescription()); + } + Cell fileNameCell = row.createCell(MACHINE_NAME_COL); + fileNameCell.setCellValue(pkgInfo.getFileName()); + Cell pkgSha1 = row.createCell(PACKAGE_SHA_COL); + if (pkgInfo.getSha1() != null) { + pkgSha1.setCellValue(pkgInfo.getSha1()); + } + // add the license infos in files in multiple rows + SPDXLicenseInfo[] licenseInfosInFiles = pkgInfo.getLicensesFromFiles(); + if (licenseInfosInFiles != null && licenseInfosInFiles.length > 0) { + StringBuilder sb = new StringBuilder(licenseInfosInFiles[0].toString()); + for (int i = 1; i < licenseInfosInFiles.length; i++) { + sb.append(","); + sb.append(licenseInfosInFiles[i].toString()); + } + row.createCell(LICENSE_INFO_IN_FILES_COL).setCellValue(sb.toString()); + } + if (pkgInfo.getLicenseComments() != null) { + row.createCell(LICENSE_COMMENT_COL).setCellValue(pkgInfo.getLicenseComments()); + } + if (pkgInfo.getShortDescription() != null) { + Cell shortDescCell = row.createCell(SHORT_DESC_COL); + shortDescCell.setCellValue(pkgInfo.getShortDescription()); + } + if (pkgInfo.getSourceInfo() != null) { + Cell sourceInfoCell = row.createCell(SOURCE_INFO_COL); + sourceInfoCell.setCellValue(pkgInfo.getSourceInfo()); + } + Cell urlCell = row.createCell(URL_COL); + urlCell.setCellValue(pkgInfo.getUrl()); + } + + public SPDXPackageInfo getPackageInfo(int rowNum) throws SpreadsheetException { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell nameCell = row.getCell(NAME_COL); + if (nameCell == null || nameCell.getStringCellValue().isEmpty()) { + return null; + } + String error = validateRow(row); + if (error != null && !error.isEmpty()) { + throw(new SpreadsheetException(error)); + } + String declaredName = nameCell.getStringCellValue(); + String machineName = row.getCell(MACHINE_NAME_COL).getStringCellValue(); + String sha1 = row.getCell(PACKAGE_SHA_COL).getStringCellValue(); + String sourceInfo; + Cell sourceInfocol = row.getCell(SOURCE_INFO_COL); + if (sourceInfocol != null) { + sourceInfo = sourceInfocol.getStringCellValue(); + } else { + sourceInfo = ""; + } + SPDXLicenseInfo declaredLicenses = + SPDXLicenseInfoFactory.parseSPDXLicenseString(row.getCell(DECLARED_LICENSE_COL).getStringCellValue()); + SPDXLicenseInfo concludedLicense; + Cell concludedLicensesCell = row.getCell(CONCLUDED_LICENSE_COL); + if (concludedLicensesCell != null && !concludedLicensesCell.getStringCellValue().isEmpty()) { + concludedLicense = SPDXLicenseInfoFactory.parseSPDXLicenseString(concludedLicensesCell.getStringCellValue()); + } else { + concludedLicense = new SPDXNoneLicense(); + } + String[] licenseStrings = row.getCell(LICENSE_INFO_IN_FILES_COL).getStringCellValue().split(","); + SPDXLicenseInfo[] licenseInfosFromFiles = new SPDXLicenseInfo[licenseStrings.length]; + for (int i = 0; i < licenseStrings.length; i++) { + licenseInfosFromFiles[i] = SPDXLicenseInfoFactory.parseSPDXLicenseString(licenseStrings[i].trim()); + } + Cell licenseCommentCell = row.getCell(LICENSE_COMMENT_COL); + String licenseComment; + if (licenseCommentCell != null && !licenseCommentCell.getStringCellValue().isEmpty()) { + licenseComment = licenseCommentCell.getStringCellValue(); + } else { + licenseComment = ""; + } + String declaredCopyright = row.getCell(DECLARED_COPYRIGHT_COL).getStringCellValue(); + Cell shortDescCell = row.getCell(SHORT_DESC_COL); + String shortDesc; + if (shortDescCell != null && !shortDescCell.getStringCellValue().isEmpty()) { + shortDesc = shortDescCell.getStringCellValue(); + } else { + shortDesc = ""; + } + Cell descCell = row.getCell(FULL_DESC_COL); + String description; + if (descCell != null && !descCell.getStringCellValue().isEmpty()) { + description = descCell.getStringCellValue(); + } else { + description = ""; + } + String url = row.getCell(URL_COL).getStringCellValue(); + String packageVerificationValue = row.getCell(FILE_VERIFICATION_VALUE_COL).getStringCellValue(); + String[] excludedFiles; + String excludedFilesStr = row.getCell(VERIFICATION_EXCLUDED_FILES_COL).getStringCellValue(); + if (excludedFilesStr != null && !excludedFilesStr.isEmpty()) { + excludedFiles = excludedFilesStr.split(","); + for (int i = 0;i < excludedFiles.length; i++) { + excludedFiles[i] = excludedFiles[i].trim(); + } + } else { + excludedFiles = new String[0]; + } + SpdxPackageVerificationCode verificationCode = new SpdxPackageVerificationCode(packageVerificationValue, excludedFiles); + String notAvailable = "Not available from spreadsheet"; + return new SPDXPackageInfo(declaredName, notAvailable, machineName, sha1, sourceInfo, + declaredLicenses, concludedLicense, licenseInfosFromFiles, + licenseComment, declaredCopyright, shortDesc, + description, url, verificationCode, "", ""); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PerFileSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PerFileSheet.java new file mode 100644 index 000000000..170cff1df --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/PerFileSheet.java @@ -0,0 +1,273 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.DOAPProject; +import org.spdx.rdfparser.InvalidSPDXAnalysisException; +import org.spdx.rdfparser.SPDXFile; +import org.spdx.rdfparser.SPDXLicenseInfo; +import org.spdx.rdfparser.SPDXLicenseInfoFactory; + +/** + * Sheet describing the per file information in an SPDX Document + * @author Gary O'Neall + * + */ +public class PerFileSheet extends AbstractSheet { + + static final int NUM_COLS = 10; + static final int FILE_NAME_COL = 0; + static final int FILE_TYPE_COL = FILE_NAME_COL + 1; + static final int SHA1_COL = FILE_TYPE_COL + 1; + static final int CONCLUDED_LIC_COL = SHA1_COL + 1; + static final int LIC_INFO_IN_FILE_COL = CONCLUDED_LIC_COL + 1; + static final int LIC_COMMENTS_COL = LIC_INFO_IN_FILE_COL + 1; + static final int SEEN_COPYRIGHT_COL = LIC_COMMENTS_COL + 1; + static final int ARTIFACT_OF_PROJECT_COL = SEEN_COPYRIGHT_COL + 1; + static final int ARTIFACT_OF_HOMEPAGE_COL = ARTIFACT_OF_PROJECT_COL + 1; + static final int ARTIFACT_OF_PROJECT_URL_COL = ARTIFACT_OF_HOMEPAGE_COL + 1; + + static final boolean[] REQUIRED = new boolean[] {true, true, false, false, + false, false, false, false, false, false}; + static final String[] HEADER_TITLES = new String[] {"File Name", "File Type", + "File Checksum", "License Concluded", "License Info in File", "License Comments", + "File Copyright Text", "Artifact of Project", "Artifact of Homepage", + "Artifact of URL"}; + static final int[] COLUMN_WIDTHS = new int[] {60, 10, 25, 30, 30, 40, + 40, 25, 60, 60}; + static final boolean[] LEFT_WRAP = new boolean[] {true, false, true, + true, true, true, true, true, true, true}; + static final boolean[] CENTER_NOWRAP = new boolean[] {false, true, false, + false, false, false, false, false, false, false}; + + + @SuppressWarnings("unused") + private String version; + + /** + * @param workbook + * @param sheetName + * @param version + */ + public PerFileSheet(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName); + this.version = version; + } + + public void add(SPDXFile fileInfo) { + Row row = addRow(); + if (fileInfo.getArtifactOf() != null && fileInfo.getArtifactOf().length > 0) { + // currently, this is restricted to only 0 or zero + DOAPProject project = fileInfo.getArtifactOf()[0]; + row.createCell(ARTIFACT_OF_PROJECT_COL).setCellValue(project.getName()); + row.createCell(ARTIFACT_OF_HOMEPAGE_COL).setCellValue(project.getHomePage()); + row.createCell(ARTIFACT_OF_PROJECT_URL_COL).setCellValue(project.getProjectUri()); + } + if (fileInfo.getConcludedLicenses() != null) { + row.createCell(CONCLUDED_LIC_COL).setCellValue(fileInfo.getConcludedLicenses().toString()); + } + row.createCell(FILE_NAME_COL).setCellValue(fileInfo.getName()); + if (fileInfo.getSha1() != null && !fileInfo.getSha1().isEmpty()) { + row.createCell(SHA1_COL).setCellValue(fileInfo.getSha1()); + } + row.createCell(FILE_TYPE_COL).setCellValue(fileInfo.getType()); + if (fileInfo.getLicenseComments() != null && !fileInfo.getLicenseComments().isEmpty()) { + row.createCell(LIC_COMMENTS_COL).setCellValue(fileInfo.getLicenseComments()); + } + if (fileInfo.getCopyright() != null && !fileInfo.getCopyright().isEmpty()) { + row.createCell(SEEN_COPYRIGHT_COL).setCellValue(fileInfo.getCopyright()); + } + if (fileInfo.getSeenLicenses() != null && fileInfo.getSeenLicenses().length > 0) { + row.createCell(LIC_INFO_IN_FILE_COL).setCellValue(PackageInfoSheetV09d2.licensesToString(fileInfo.getSeenLicenses())); + } + } + + public SPDXFile getFileInfo(int rowNum) throws SpreadsheetException { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + String ver = validateRow(row); + if (ver != null && !ver.isEmpty()) { + throw(new SpreadsheetException(ver)); + } + String name = row.getCell(FILE_NAME_COL).getStringCellValue(); + String type = row.getCell(FILE_TYPE_COL).getStringCellValue(); + Cell sha1cell = row.getCell(SHA1_COL); + String sha1; + if (sha1cell != null) { + sha1 = sha1cell.getStringCellValue(); + } else { + sha1 = ""; + } + SPDXLicenseInfo fileLicenses; + Cell assertedLicenseCell = row.getCell(CONCLUDED_LIC_COL); + if (assertedLicenseCell != null && !assertedLicenseCell.getStringCellValue().isEmpty()) { + fileLicenses = SPDXLicenseInfoFactory.parseSPDXLicenseString(assertedLicenseCell.getStringCellValue()); + } else { + fileLicenses = null; + } + SPDXLicenseInfo[] seenLicenses; + Cell seenLicenseCell = row.getCell(LIC_INFO_IN_FILE_COL); + if (seenLicenseCell != null && !seenLicenseCell.getStringCellValue().isEmpty()) { + String[] licenseStrings = seenLicenseCell.getStringCellValue().split(","); + seenLicenses = new SPDXLicenseInfo[licenseStrings.length]; + for (int i = 0; i < licenseStrings.length; i++) { + seenLicenses[i] = SPDXLicenseInfoFactory.parseSPDXLicenseString(licenseStrings[i].trim()); + } + } else { + seenLicenses = null; + } + String licenseComments; + Cell licCommentCell = row.getCell(LIC_COMMENTS_COL); + if (licCommentCell != null) { + licenseComments = licCommentCell.getStringCellValue(); + } else { + licenseComments = ""; + } + String copyright; + Cell copyrightCell = row.getCell(SEEN_COPYRIGHT_COL); + if (copyrightCell != null) { + copyright = copyrightCell.getStringCellValue(); + } else { + copyright = ""; + } + DOAPProject[] artifactOf; + Cell artifactOfCell = row.getCell(ARTIFACT_OF_PROJECT_COL); + if (artifactOfCell != null && !artifactOfCell.getStringCellValue().isEmpty()) { + String projectName = artifactOfCell.getStringCellValue(); + String homePage = ""; + Cell homePageCell = row.getCell(ARTIFACT_OF_HOMEPAGE_COL); + if (homePageCell != null) { + homePage = homePageCell.getStringCellValue(); + } + Cell uriCell = row.getCell(ARTIFACT_OF_PROJECT_URL_COL); + String uri = ""; + if (uriCell != null) { + uri = uriCell.getStringCellValue(); + } + DOAPProject project = new DOAPProject(projectName, homePage); + if (uri != null && !uri.isEmpty()) { + try { + project.setUri(uri); + } catch (InvalidSPDXAnalysisException e) { + throw new SpreadsheetException("Error setting the URI for the artifact of"); + } + } + artifactOf = new DOAPProject[] {project}; + } else { + artifactOf = new DOAPProject[0]; + } + return new SPDXFile(name, type, sha1, fileLicenses, + seenLicenses, licenseComments, copyright, artifactOf); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSheet#verify() + */ + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX File does not exist"; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX File worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX File work sheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + if (REQUIRED[i]) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum()); + } + } else { +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + if (i == CONCLUDED_LIC_COL || i == LIC_INFO_IN_FILE_COL) { + try { + SPDXLicenseInfoFactory.parseSPDXLicenseString(cell.getStringCellValue()); + } catch (SpreadsheetException ex) { + if (i == CONCLUDED_LIC_COL) { + return "Invalid asserted license string in row "+String.valueOf(row.getRowNum()) + + " details: "+ex.getMessage(); + } else { + return "Invalid seen license string in row "+String.valueOf(row.getRowNum()) + + " details: "+ex.getMessage(); + } + } + } + } + } + return null; + } + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle centerStyle = AbstractSheet.createCenterStyle(wb); + CellStyle wrapStyle = AbstractSheet.createLeftWrapStyle(wb); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + if (LEFT_WRAP[i]) { + sheet.setDefaultColumnStyle(i, wrapStyle); + } else if (CENTER_NOWRAP[i]) { + sheet.setDefaultColumnStyle(i, centerStyle); + } + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/RdfToSpreadsheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/RdfToSpreadsheet.java new file mode 100644 index 000000000..a138ddb65 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/RdfToSpreadsheet.java @@ -0,0 +1,197 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.regex.Pattern; + +import org.spdx.rdfparser.InvalidSPDXAnalysisException; +import org.spdx.rdfparser.SPDXCreatorInformation; +import org.spdx.rdfparser.SPDXDocument; +import org.spdx.rdfparser.SPDXDocument.SPDXPackage; +import org.spdx.rdfparser.SPDXDocumentFactory; +import org.spdx.rdfparser.SPDXFile; +import org.spdx.rdfparser.SPDXNonStandardLicense; +import org.spdx.rdfparser.SPDXReview; +import org.spdx.rdfparser.SPDXPackageInfo; +import org.spdx.rdfparser.SPDXStandardLicense; +import org.spdx.rdfparser.SpdxRdfConstants; + +/** + * Translates an RDF XML file to a SPDX Spreadsheet format + * Usage: RdfToSpreadsheet rdfxmlfile.rdf spreadsheetfile.xls + * where rdfxmlfile.rdf is a valid SPDX RDF XML file and spreadsheetfile.xls is + * the output SPDX spreadsheeet file. + * @author Gary O'Neall + * + */ +public class RdfToSpreadsheet { + + static final int MIN_ARGS = 2; + static final int MAX_ARGS = 2; + static Pattern datePattern = Pattern.compile(".. ... \\d\\d\\d\\d \\d\\d:\\d\\d:\\d\\d GMT$"); + public static final String NOT_SUPPORTED_STRING = "This field is not yet supported by SPDX"; + /** + * @param args + */ + public static void main(String[] args) { + if (args.length < MIN_ARGS) { + usage(); + return; + } + if (args.length > MAX_ARGS) { + usage(); + return; + } + File spdxRdfFile = new File(args[0]); + if (!spdxRdfFile.exists()) { + System.out.printf("Error: File %1$s does not exist.\n", args[0]); + return; + } + File spdxSpreadsheetFile = new File(args[1]); + if (spdxSpreadsheetFile.exists()) { + System.out.println("Spreadsheet file already exists - please specify a new file."); + return; + } + SPDXDocument doc = null; + try { + doc = SPDXDocumentFactory.creatSpdxDocument(args[0]); + } catch (InvalidSPDXAnalysisException ex) { + System.out.print("Error creating SPDX Document: "+ex.getMessage()); + return; + } catch (IOException e) { + System.out.print("Unable to open file :"+args[0]+", "+e.getMessage()); + } + SPDXSpreadsheet ss = null; + try { + ss = new SPDXSpreadsheet(spdxSpreadsheetFile, true, false); + copyRdfXmlToSpreadsheet(doc, ss); + ArrayList verify = doc.verify(); + if (verify.size() > 0) { + System.out.println("Warning: The following verifications failed for the resultant SPDX RDF file:"); + for (int i = 0; i < verify.size(); i++) { + System.out.println("\t"+verify.get(i)); + } + } + } catch (SpreadsheetException e) { + System.out.println("Error opening or writing to spreadsheet: "+e.getMessage()); + } catch (InvalidSPDXAnalysisException e) { + System.out.println("Error translating the RDF file: "+e.getMessage()); + } catch (Exception ex) { + System.out.println("Unexpected error translating the RDF to spreadsheet: "+ex.getMessage()); + } finally { + if (ss != null) { + try { + ss.close(); + } catch (SpreadsheetException e) { + System.out.println("Error closing spreadsheet: "+e.getMessage()); + } + } + } + } + + public static void copyRdfXmlToSpreadsheet(SPDXDocument doc, + SPDXSpreadsheet ss) throws InvalidSPDXAnalysisException { + if (doc == null) { + System.out.println("Warning: No document to copy"); + return; + } + copyOrigins(doc, ss.getOriginsSheet()); + copyPackageInfo(doc.getSpdxPackage(), ss.getPackageInfoSheet()); + copyNonStdLicenses(doc.getExtractedLicenseInfos(), ss.getNonStandardLicensesSheet()); + copyPerFileInfo(doc.getSpdxPackage().getFiles(), ss.getPerFileSheet()); + copyReviewerInfo(doc.getReviewers(), ss.getReviewersSheet()); + } + + private static void copyReviewerInfo(SPDXReview[] reviewers, + ReviewersSheet reviewersSheet) throws InvalidSPDXAnalysisException { + DateFormat dateFormat = new SimpleDateFormat(SpdxRdfConstants.SPDX_DATE_FORMAT); + for (int i = 0; i < reviewers.length; i++) { + String reviewerName = reviewers[i].getReviewer(); + Date reviewDate = null; + String dateString = reviewers[i].getReviewDate(); + if (dateString != null && !dateString.isEmpty()) { + try { + dateString = dateString.trim(); + reviewDate = dateFormat.parse(dateString); + } catch (Exception ex) { + throw(new InvalidSPDXAnalysisException("Invalid reviewer date format for reviewer "+reviewers[i])); + } + } + reviewersSheet.addReviewer(reviewerName, reviewDate, reviewers[i].getComment()); + } + } + + private static void copyPerFileInfo(SPDXFile[] files, + PerFileSheet perFileSheet) { + for (int i = 0; i < files.length; i++) { + perFileSheet.add(files[i]); + } + } + + private static void copyNonStdLicenses(SPDXNonStandardLicense[] nonStandardLicenses, + NonStandardLicensesSheet nonStandardLicensesSheet) { + for(int i = 0; i < nonStandardLicenses.length; i++) { + nonStandardLicensesSheet.add(nonStandardLicenses[i].getId(), nonStandardLicenses[i].getText()); + } + } + + private static void copyPackageInfo(SPDXPackage spdxPackage, + PackageInfoSheet packageInfoSheet) throws InvalidSPDXAnalysisException { + SPDXPackageInfo pkgInfo = spdxPackage.getPackageInfo(); + packageInfoSheet.add(pkgInfo); + } + + private static void copyOrigins(SPDXDocument doc, OriginsSheet originsSheet) throws InvalidSPDXAnalysisException { + // SPDX Version + originsSheet.setSPDXVersion(doc.getSpdxVersion()); + // Created by + SPDXCreatorInformation creator = doc.getCreatorInfo(); + String[] createdBys = creator.getCreators(); + originsSheet.setCreatedBy(createdBys); + // Data license + SPDXStandardLicense dataLicense = doc.getDataLicense(); + if (dataLicense != null) { + originsSheet.setDataLicense(dataLicense.getId()); + } + // Author Comments + String comments = creator.getComment(); + if (comments != null && !comments.isEmpty()) { + originsSheet.setAuthorComments(comments); + } + String created = creator.getCreated(); + DateFormat dateFormat = new SimpleDateFormat(SpdxRdfConstants.SPDX_DATE_FORMAT); + try { + originsSheet.setCreated(dateFormat.parse(created)); + } catch (ParseException e) { + throw(new InvalidSPDXAnalysisException("Invalid created date - unable to parse")); + } + + } + + private static void usage() { + System.out.println("Usage: RdfToSpreadsheet rdfxmlfile.rdf spreadsheetfile.xls\n"+ + "where rdfxmlfile.rdf is a valid SPDX RDF XML file and spreadsheetfile.xls is\n"+ + "the output SPDX spreadsheeet file."); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/ReviewersSheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/ReviewersSheet.java new file mode 100644 index 000000000..96a916742 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/ReviewersSheet.java @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.util.Date; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * Sheet describing any reviewers for an SPDX Document + * @author Gary O'Neall + * + */ +public class ReviewersSheet extends AbstractSheet { + + static final int NUM_COLS = 3; + static final int REVIEWER_COL = 0; + static final int TIMESTAMP_COL = REVIEWER_COL + 1; + static final int COMMENT_COL = TIMESTAMP_COL + 1; + static final String[] HEADER_TITLES = new String[] {"Reviewer", "Review Date", "Reviewer Comment"}; + static final int[] COLUMN_WIDTHS = new int[] {60, 20, 120}; + static final boolean[] LEFT_WRAP = new boolean[] {true, false, true}; + static final boolean[] CENTER_NOWRAP = new boolean[] {false, true, false}; + + static final boolean[] REQUIRED = new boolean[] {true, true, false}; + + @SuppressWarnings("unused") + private String version; + + public ReviewersSheet(Workbook workbook, String sheetName, String version) { + super(workbook, sheetName); + this.version = version; + } + + @Override + public String verify() { + try { + if (sheet == null) { + return "Worksheet for SPDX Reviewers does not exist"; + } + Row firstRow = sheet.getRow(firstRowNum); + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = firstRow.getCell(i+firstCellNum); + if (cell == null || + cell.getStringCellValue() == null || + !cell.getStringCellValue().equals(HEADER_TITLES[i])) { + return "Column "+HEADER_TITLES[i]+" missing for SPDX Reviewers worksheet"; + } + } + // validate rows + boolean done = false; + int rowNum = firstRowNum + 1; + while (!done) { + Row row = sheet.getRow(rowNum); + if (row == null || row.getCell(firstCellNum) == null) { + done = true; + } else { + String error = validateRow(row); + if (error != null) { + return error; + } + rowNum++; + } + } + return null; + } catch (Exception ex) { + return "Error in verifying SPDX Reviewers worksheet: "+ex.getMessage(); + } + } + + private String validateRow(Row row) { + for (int i = 0; i < NUM_COLS; i++) { + Cell cell = row.getCell(i); + if (REQUIRED[i] && cell == null) { + return "Required cell "+HEADER_TITLES[i]+" missing for row "+String.valueOf(row.getRowNum())+" in reviewer sheet"; + } else { + if (i == TIMESTAMP_COL) { + if (!(cell.getCellType() == Cell.CELL_TYPE_NUMERIC)) { + return "Timestamp cell is not a numeric type for row "+String.valueOf(row.getRowNum())+" in Reviewer sheet"; + } + } +// if (cell.getCellType() != Cell.CELL_TYPE_STRING) { +// return "Invalid cell format for "+HEADER_TITLES[i]+" for forw "+String.valueOf(row.getRowNum()); +// } + } + } + return null; + } + + public static void create(Workbook wb, String sheetName) { + int sheetNum = wb.getSheetIndex(sheetName); + if (sheetNum >= 0) { + wb.removeSheetAt(sheetNum); + } + Sheet sheet = wb.createSheet(sheetName); + CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb); + CellStyle centerStyle = AbstractSheet.createCenterStyle(wb); + CellStyle wrapStyle = AbstractSheet.createLeftWrapStyle(wb); + Row row = sheet.createRow(0); + for (int i = 0; i < HEADER_TITLES.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i]*256); + if (LEFT_WRAP[i]) { + sheet.setDefaultColumnStyle(i, wrapStyle); + } else if (CENTER_NOWRAP[i]) { + sheet.setDefaultColumnStyle(i, centerStyle); + } + Cell cell = row.createCell(i); + cell.setCellStyle(headerStyle); + cell.setCellValue(HEADER_TITLES[i]); + } + } + + public void addReviewer(String reviewer, Date timeStamp, String reviewerComment) { + Row row = addRow(); + row.createCell(REVIEWER_COL).setCellValue(reviewer); + Cell dateCell = row.createCell(TIMESTAMP_COL); + if (timeStamp != null) { + dateCell.setCellValue(timeStamp); + dateCell.setCellStyle(dateStyle); + } + if (reviewerComment != null && !reviewerComment.isEmpty()) { + row.createCell(COMMENT_COL).setCellValue(reviewerComment); + } + } + + public String getReviewer(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell reviewer = row.getCell(REVIEWER_COL); + if (reviewer == null) { + return null; + } + return reviewer.getStringCellValue(); + } + + public Date getReviewerTimestamp(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell tsCell = row.getCell(TIMESTAMP_COL); + if (tsCell == null) { + return null; + } + return tsCell.getDateCellValue(); + } + + public String getReviewerComment(int rowNum) { + Row row = sheet.getRow(rowNum); + if (row == null) { + return null; + } + Cell commentCell = row.getCell(COMMENT_COL); + if (commentCell == null) { + return null; + } + return commentCell.getStringCellValue(); + } +} \ No newline at end of file diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXLicenseSpreadsheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXLicenseSpreadsheet.java new file mode 100644 index 000000000..222c63180 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXLicenseSpreadsheet.java @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.spdx.rdfparser.LicenseSheet; +import org.spdx.rdfparser.SPDXStandardLicense; + +/** + * A spreadhseet containing license information + * @author Source Auditor + * + */ +public class SPDXLicenseSpreadsheet extends AbstractSpreadsheet { + + public class LicenseIterator implements Iterator { + + private int currentRowNum; + SPDXStandardLicense currentLicense; + public LicenseIterator() { + this.currentRowNum = 2; // skip past header row + currentLicense = licenseSheet.getLicense(currentRowNum); + } + @Override + public boolean hasNext() { + if (currentLicense == null) { + return false; + } else { + return true; + } + } + + @Override + public SPDXStandardLicense next() { + SPDXStandardLicense retval = currentLicense; + currentRowNum++; + currentLicense = licenseSheet.getLicense(currentRowNum); + return retval; + } + + @Override + public void remove() { + // not implementd + } + + } + static final String LICENSE_SHEET_NAME = "Licenses"; + + private LicenseSheet licenseSheet; + + public SPDXLicenseSpreadsheet(File spreadsheetFile, boolean create, boolean readonly) + throws SpreadsheetException { + super(spreadsheetFile, create, readonly); + this.licenseSheet = new LicenseSheet(this.workbook, LICENSE_SHEET_NAME); + String verifyMsg = verifyWorkbook(); + if (verifyMsg != null) { + logger.error(verifyMsg); + throw(new SpreadsheetException(verifyMsg)); + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#create(java.io.File) + */ + @Override + public void create(File spreadsheetFile) throws IOException, + SpreadsheetException { + if (!spreadsheetFile.createNewFile()) { + logger.error("Unable to create "+spreadsheetFile.getName()); + throw(new SpreadsheetException("Unable to create "+spreadsheetFile.getName())); + } + FileOutputStream excelOut = null; + try { + excelOut = new FileOutputStream(spreadsheetFile); + Workbook wb = new HSSFWorkbook(); + LicenseSheet.create(wb, LICENSE_SHEET_NAME); + wb.write(excelOut); + } finally { + excelOut.close(); + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#clear() + */ + @Override + public void clear() { + this.licenseSheet.clear(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#verifyWorkbook() + */ + @Override + public String verifyWorkbook() { + return this.licenseSheet.verify(); + } + + /** + * @return the licenseSheet + */ + public LicenseSheet getLicenseSheet() { + return licenseSheet; + } + + public Iterator getIterator() { + return new LicenseIterator(); + } + + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXSpreadsheet.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXSpreadsheet.java new file mode 100644 index 000000000..eecc1f9d2 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SPDXSpreadsheet.java @@ -0,0 +1,214 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * A spreadsheet containing information on an SPDX Document. + * + * The spreadsheet contains 4 sheets: + * - Origins - Information about the origin of the SPDX Document (Version, createdby, ...) + * - Package Info - Information about the package itself + * - Non-standard licenses - text from any non-standard licenses found + * - Per File Info - Information about each file in the document + * - Reviewers - Information on any organizations who have reviewed the documents + * @author Gary O'Neall + * + */ +public class SPDXSpreadsheet extends AbstractSpreadsheet { + + private OriginsSheet originsSheet; + static final String ORIGIN_SHEET_NAME = "Origins"; + private PackageInfoSheet packageInfoSheet; + static final String PACKAGE_INFO_SHEET_NAME = "Package Info"; + private NonStandardLicensesSheet nonStandardLicensesSheet; + static final String NON_STANDARD_LICENSE_SHEET_NAME = "Extracted Lic Info"; + private PerFileSheet perFileSheet; + static final String PER_FILE_SHEET_NAME = "Per File Info"; + private ReviewersSheet reviewersSheet; + static final String REVIEWERS_SHEET_NAME = "Reviewers"; + private String version; + + /** + * @param spreadsheetFile + * @param create + * @param readonly + * @throws SpreadsheetException + */ + public SPDXSpreadsheet(File spreadsheetFile, boolean create, + boolean readonly) throws SpreadsheetException { + super(spreadsheetFile, create, readonly); + this.originsSheet = new OriginsSheet(this.workbook, ORIGIN_SHEET_NAME); + String verifyMsg = originsSheet.verify(); + if (verifyMsg != null) { + logger.error(verifyMsg); + throw(new SpreadsheetException(verifyMsg)); + } + this.version = this.originsSheet.getSpreadsheetVersion(); + if (this.version.equals(OriginsSheet.VERSION_0_9_1)) { + this.packageInfoSheet = new PackageInfoSheetV9d1(this.workbook, PACKAGE_INFO_SHEET_NAME, version); + } else if (this.version.equals(OriginsSheet.VERSION_0_9_2)) { + this.packageInfoSheet = new PackageInfoSheetV09d2(this.workbook, PACKAGE_INFO_SHEET_NAME, version); + } else { + this.packageInfoSheet = new PackageInfoSheetV09d3(this.workbook, PACKAGE_INFO_SHEET_NAME, version); + } + this.nonStandardLicensesSheet = new NonStandardLicensesSheet(this.workbook, NON_STANDARD_LICENSE_SHEET_NAME, version); + this.perFileSheet = new PerFileSheet(this.workbook, PER_FILE_SHEET_NAME, version); + this.reviewersSheet = new ReviewersSheet(this.workbook, REVIEWERS_SHEET_NAME, version); + verifyMsg = verifyWorkbook(); + if (verifyMsg != null) { + logger.error(verifyMsg); + throw(new SpreadsheetException(verifyMsg)); + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#create(java.io.File) + */ + @Override + public void create(File spreadsheetFile) throws IOException, + SpreadsheetException { + if (!spreadsheetFile.createNewFile()) { + logger.error("Unable to create "+spreadsheetFile.getName()); + throw(new SpreadsheetException("Unable to create "+spreadsheetFile.getName())); + } + FileOutputStream excelOut = null; + try { + excelOut = new FileOutputStream(spreadsheetFile); + Workbook wb = new HSSFWorkbook(); + OriginsSheet.create(wb, ORIGIN_SHEET_NAME); + PackageInfoSheetV09d3.create(wb, PACKAGE_INFO_SHEET_NAME); + NonStandardLicensesSheet.create(wb, NON_STANDARD_LICENSE_SHEET_NAME); + PerFileSheet.create(wb, PER_FILE_SHEET_NAME); + ReviewersSheet.create(wb, REVIEWERS_SHEET_NAME); + wb.write(excelOut); + } finally { + excelOut.close(); + } + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#clear() + */ + @Override + public void clear() { + this.originsSheet.clear(); + this.packageInfoSheet.clear(); + this.nonStandardLicensesSheet.clear(); + this.perFileSheet.clear(); + this.reviewersSheet.clear(); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.AbstractSpreadsheet#verifyWorkbook() + */ + @Override + public String verifyWorkbook() { + String retval = this.originsSheet.verify(); + if (retval == null || retval.isEmpty()) { + retval = this.packageInfoSheet.verify(); + } + if (retval == null || retval.isEmpty()) { + retval = this.nonStandardLicensesSheet.verify(); + } + if (retval == null || retval.isEmpty()) { + retval = this.perFileSheet.verify(); + } + if (retval == null || retval.isEmpty()) { + retval = this.reviewersSheet.verify(); + } + return retval; + } + + /** + * @return the originsSheet + */ + public OriginsSheet getOriginsSheet() { + return originsSheet; + } + + /** + * @param originsSheet the originsSheet to set + */ + public void setOriginsSheet(OriginsSheet originsSheet) { + this.originsSheet = originsSheet; + } + + /** + * @return the packageInfoSheet + */ + public PackageInfoSheet getPackageInfoSheet() { + return packageInfoSheet; + } + + /** + * @param packageInfoSheet the packageInfoSheet to set + */ + public void setPackageInfoSheet(PackageInfoSheetV09d2 packageInfoSheet) { + this.packageInfoSheet = packageInfoSheet; + } + + /** + * @return the nonStandardLicensesSheet + */ + public NonStandardLicensesSheet getNonStandardLicensesSheet() { + return nonStandardLicensesSheet; + } + + /** + * @param nonStandardLicensesSheet the nonStandardLicensesSheet to set + */ + public void setNonStandardLicensesSheet( + NonStandardLicensesSheet nonStandardLicensesSheet) { + this.nonStandardLicensesSheet = nonStandardLicensesSheet; + } + + /** + * @return the perFileSheet + */ + public PerFileSheet getPerFileSheet() { + return perFileSheet; + } + + /** + * @param perFileSheet the perFileSheet to set + */ + public void setPerFileSheet(PerFileSheet perFileSheet) { + this.perFileSheet = perFileSheet; + } + + /** + * @return the reviewersSheet + */ + public ReviewersSheet getReviewersSheet() { + return reviewersSheet; + } + + /** + * @param reviewersSheet the reviewersSheet to set + */ + public void setReviewersSheet(ReviewersSheet reviewersSheet) { + this.reviewersSheet = reviewersSheet; + } + +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetException.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetException.java new file mode 100644 index 000000000..395b7cab9 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetException.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 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.spdxspreadsheet; + +public class SpreadsheetException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -5174679000954342942L; + + public SpreadsheetException(String message) { + super(message); + } + + public SpreadsheetException(String message, Throwable inner) { + super(message, inner); + } +} diff --git a/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetToRDF.java b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetToRDF.java new file mode 100644 index 000000000..bcdb67a34 --- /dev/null +++ b/TestFiles/spdx-parser-source/org/spdx/spdxspreadsheet/SpreadsheetToRDF.java @@ -0,0 +1,251 @@ +/** + * Copyright (c) 2011 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.spdxspreadsheet; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; + +import org.spdx.rdfparser.InvalidSPDXAnalysisException; +import org.spdx.rdfparser.SPDXCreatorInformation; +import org.spdx.rdfparser.SPDXDocument; +import org.spdx.rdfparser.SPDXDocument.SPDXPackage; +import org.spdx.rdfparser.SPDXFile; +import org.spdx.rdfparser.SPDXLicenseInfoFactory; +import org.spdx.rdfparser.SPDXNonStandardLicense; +import org.spdx.rdfparser.SPDXReview; +import org.spdx.rdfparser.SPDXPackageInfo; +import org.spdx.rdfparser.SPDXStandardLicense; +import org.spdx.rdfparser.SpdxRdfConstants; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; + +/** + * Converts a spreadsheet to an SPDX RDF Analysis file + * Usage: SpreadsheetToRDF spreadsheetfile.xls rdfxmlfile.rdf + * where spreadsheetfile.xls is a valid SPDX Spreadsheet and + * rdfxmlfile.rdf is the output SPDX RDF Analysis file. + * @author Gary O'Neall + * + */ +public class SpreadsheetToRDF { + + static final int MIN_ARGS = 2; + static final int MAX_ARGS = 2; + static DateFormat format = new SimpleDateFormat(SpdxRdfConstants.SPDX_DATE_FORMAT); + + /** + * @param args + */ + public static void main(String[] args) { + if (args.length < MIN_ARGS) { + usage(); + return; + } + if (args.length > MAX_ARGS) { + usage(); + return; + } + File spdxSpreadsheetFile = new File(args[0]); + if (!spdxSpreadsheetFile.exists()) { + System.out.printf("Spreadsheet file %1$s does not exists.\n", args[0]); + return; + } + File spdxRdfFile = new File(args[1]); + if (spdxRdfFile.exists()) { + System.out.printf("Error: File %1$s already exists - please specify a new file.\n", args[1]); + return; + } + + try { + if (!spdxRdfFile.createNewFile()) { + System.out.println("Could not create the new SPDX RDF file "+args[1]); + usage(); + return; + } + } catch (IOException e1) { + System.out.println("Could not create the new SPDX RDF file "+args[1]); + System.out.println("due to error "+e1.getMessage()); + usage(); + return; + } + FileOutputStream out; + try { + out = new FileOutputStream(spdxRdfFile); + } catch (FileNotFoundException e1) { + System.out.println("Could not write to the new SPDX RDF file "+args[1]); + System.out.println("due to error "+e1.getMessage()); + usage(); + return; + } + Model model = ModelFactory.createDefaultModel(); + SPDXDocument analysis = null; + try { + analysis = new SPDXDocument(model); + } catch (InvalidSPDXAnalysisException ex) { + System.out.print("Error creating SPDX Analysis: "+ex.getMessage()); + return; + } + SPDXSpreadsheet ss = null; + try { + ss = new SPDXSpreadsheet(spdxSpreadsheetFile, false, true); + copySpreadsheetToSPDXAnalysis(ss, analysis); + ArrayList verify = analysis.verify(); + if (verify.size() > 0) { + System.out.println("Warning: The following verification errors were found in the resultant SPDX Document:"); + for (int i = 0; i < verify.size(); i++) { + System.out.println("\t"+verify.get(i)); + } + } + model.write(out, "RDF/XML-ABBREV"); + } catch (SpreadsheetException e) { + System.out.println("Error creating or writing to spreadsheet: "+e.getMessage()); + } catch (InvalidSPDXAnalysisException e) { + System.out.println("Error translating the RDF file: "+e.getMessage()); + } finally { + if (ss != null) { + try { + ss.close(); + } catch (SpreadsheetException e) { + System.out.println("Error closing spreadsheet: "+e.getMessage()); + } + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + System.out.println("Error closing RDF file: "+e.getMessage()); + } + } + } + } + + private static void copySpreadsheetToSPDXAnalysis(SPDXSpreadsheet ss, + SPDXDocument analysis) throws SpreadsheetException, InvalidSPDXAnalysisException { + analysis.createSpdxAnalysis(ss.getPackageInfoSheet().getPackageInfo(1).getUrl()+"#SPDXANALYSIS"); + copyOrigins(ss.getOriginsSheet(), analysis); + analysis.createSpdxPackage(); + copyNonStdLicenses(ss.getNonStandardLicensesSheet(), analysis); + // note - non std licenses must be added first so that the text is available + copyPackageInfo(ss.getPackageInfoSheet(), analysis.getSpdxPackage()); + copyPerFileInfo(ss.getPerFileSheet(), analysis.getSpdxPackage()); + copyReviewerInfo(ss.getReviewersSheet(), analysis); + + } + + private static void copyReviewerInfo(ReviewersSheet reviewersSheet, + SPDXDocument analysis) throws InvalidSPDXAnalysisException { + int numReviewers = reviewersSheet.getNumDataRows(); + int firstRow = reviewersSheet.getFirstDataRow(); + SPDXReview[] reviewers = new SPDXReview[numReviewers]; + for (int i = 0; i < reviewers.length; i++) { + reviewers[i] = new SPDXReview(reviewersSheet.getReviewer(firstRow+i), format.format(reviewersSheet.getReviewerTimestamp(firstRow+i)), + reviewersSheet.getReviewerComment(firstRow + i)); + } + analysis.setReviewers(reviewers); + } + + private static void copyPerFileInfo(PerFileSheet perFileSheet, + SPDXPackage spdxPackage) throws SpreadsheetException, InvalidSPDXAnalysisException { + int firstRow = perFileSheet.getFirstDataRow(); + SPDXFile[] files = new SPDXFile[perFileSheet.getNumDataRows()]; + for (int i = 0; i < files.length; i++) { + files[i] = perFileSheet.getFileInfo(firstRow+i); + } + spdxPackage.setFiles(files); + } + + private static void copyNonStdLicenses( + NonStandardLicensesSheet nonStandardLicensesSheet, SPDXDocument analysis) throws InvalidSPDXAnalysisException { + int numNonStdLicenses = nonStandardLicensesSheet.getNumDataRows(); + int firstRow = nonStandardLicensesSheet.getFirstDataRow(); + SPDXNonStandardLicense[] nonStdLicenses = new SPDXNonStandardLicense[numNonStdLicenses]; + for (int i = 0; i < nonStdLicenses.length; i++) { + nonStdLicenses[i] = new SPDXNonStandardLicense(nonStandardLicensesSheet.getIdentifier(firstRow+i), + nonStandardLicensesSheet.getExtractedText(firstRow+i)); + } + analysis.setExtractedLicenseInfos(nonStdLicenses); + } + + private static void copyPackageInfo(PackageInfoSheet packageInfoSheet, + SPDXPackage spdxPackage) throws SpreadsheetException, InvalidSPDXAnalysisException { + SPDXPackageInfo info = packageInfoSheet.getPackageInfo(packageInfoSheet.getFirstDataRow()); + if (info == null) { + throw(new InvalidSPDXAnalysisException("No package info in the spreadsheet")); + } + spdxPackage.setDeclaredCopyright(info.getDeclaredCopyright()); + spdxPackage.setDeclaredLicense(info.getDeclaredLicenses()); + spdxPackage.setDeclaredName(info.getDeclaredName()); + spdxPackage.setDescription(info.getDescription()); + spdxPackage.setConcludedLicenses(info.getConcludedLicense()); + spdxPackage.setLicenseInfoFromFiles(info.getLicensesFromFiles()); + spdxPackage.setLicenseComment(info.getLicenseComments()); + spdxPackage.setVerificationCode(info.getPackageVerification()); + spdxPackage.setFileName(info.getFileName()); + spdxPackage.setSha1(info.getSha1()); + spdxPackage.setShortDescription(info.getShortDescription()); + spdxPackage.setSourceInfo(info.getSourceInfo()); + spdxPackage.setDownloadUrl(info.getUrl()); + if (info.getVersionInfo() != null && !info.getVersionInfo().isEmpty()) { + spdxPackage.setVersionInfo(info.getVersionInfo()); + } + if (info.getOriginator() != null && !info.getOriginator().isEmpty()) { + spdxPackage.setOriginator(info.getOriginator()); + } + if (info.getSupplier() != null && !info.getSupplier().isEmpty()) { + spdxPackage.setSupplier(info.getSupplier()); + } + } + + private static void copyOrigins(OriginsSheet originsSheet, SPDXDocument analysis) throws InvalidSPDXAnalysisException { + Date createdDate = originsSheet.getCreated(); + String created = format.format(createdDate); + String[] createdBys = originsSheet.getCreatedBy(); + String creatorComment = originsSheet.getAuthorComments(); + SPDXCreatorInformation creator = new SPDXCreatorInformation(createdBys, created, creatorComment); + String dataLicenseId = originsSheet.getDataLicense(); + if (dataLicenseId == null || dataLicenseId.isEmpty() || dataLicenseId.equals(RdfToSpreadsheet.NOT_SUPPORTED_STRING)) { + dataLicenseId = SpdxRdfConstants.SPDX_DATA_LICENSE_ID; + } + SPDXStandardLicense dataLicense = null; + try { + dataLicense = (SPDXStandardLicense)SPDXLicenseInfoFactory.parseSPDXLicenseString(dataLicenseId); + } catch (Exception ex) { + try { + dataLicense = (SPDXStandardLicense)SPDXLicenseInfoFactory.parseSPDXLicenseString(SpdxRdfConstants.SPDX_DATA_LICENSE_ID); + } catch (InvalidLicenseStringException e) { + throw(new InvalidSPDXAnalysisException("Unable to get document license")); + } + } + analysis.setDataLicense(dataLicense); + analysis.setCreationInfo(creator); + analysis.setSpdxVersion(originsSheet.getSPDXVersion()); + } + + private static void usage() { + System.out.println("Usage: SpreadsheetToRDF spreadsheetfile.xls rdfxmlfile.rdf \n"+ + "where spreadsheetfile.xls is a valid SPDX Spreadsheet and\n"+ + "rdfxmlfile.rdf is the output SPDX RDF analysis file."); + } + +} diff --git a/src/main/java/org/spdx/utility/verificationcode/IFileChecksumGenerator.java b/src/main/java/org/spdx/utility/verificationcode/IFileChecksumGenerator.java new file mode 100644 index 000000000..ddf598dde --- /dev/null +++ b/src/main/java/org/spdx/utility/verificationcode/IFileChecksumGenerator.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2011 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.utility.verificationcode; + +import java.io.File; +import java.io.IOException; + +/** + * Interface for implementations of generators of file checksums + * @author Gary O'Neall + * + */ +public interface IFileChecksumGenerator { + public String getFileChecksum(File file) throws IOException; +} diff --git a/src/main/java/org/spdx/utility/verificationcode/JavaSha1ChecksumGenerator.java b/src/main/java/org/spdx/utility/verificationcode/JavaSha1ChecksumGenerator.java new file mode 100644 index 000000000..91a5c5110 --- /dev/null +++ b/src/main/java/org/spdx/utility/verificationcode/JavaSha1ChecksumGenerator.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2011 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.utility.verificationcode; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Java sha1 checksum generator using MessageDigest + * @author Gary O'Neall + * + */ +public class JavaSha1ChecksumGenerator implements IFileChecksumGenerator { + static final String SHA1_ALGORITHM = "SHA-1"; + static final String PACKAGE_VERIFICATION_CHARSET = "UTF-8"; + private MessageDigest digest = null; + + public JavaSha1ChecksumGenerator() throws NoSuchAlgorithmException { + this.digest = MessageDigest.getInstance(SHA1_ALGORITHM); + } + + /* (non-Javadoc) + * @see org.spdx.rdfparser.IFileChecksumGenerator#getFileChecksum(java.io.File) + */ + @Override + public String getFileChecksum(File file) throws IOException { + digest.reset(); + FileInputStream in = new FileInputStream(file); + try { + byte[] buffer = new byte[2048]; + int numBytes = in.read(buffer); + while (numBytes >= 0) { + digest.update(buffer, 0, numBytes); + numBytes = in.read(buffer); + } + byte[] digestBytes = digest.digest(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < digestBytes.length; i++) { + String hex = Integer.toHexString(0xff & digestBytes[i]); + if (hex.length() < 2) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } finally { + in.close(); + } + } + +} diff --git a/src/main/java/org/spdx/utility/verificationcode/VerificationCodeGenerator.java b/src/main/java/org/spdx/utility/verificationcode/VerificationCodeGenerator.java new file mode 100644 index 000000000..6bb49879c --- /dev/null +++ b/src/main/java/org/spdx/utility/verificationcode/VerificationCodeGenerator.java @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2011 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.utility.verificationcode; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.library.model.SpdxFile; +import org.spdx.library.model.SpdxPackageVerificationCode; +import org.spdx.storage.IModelStore; +import org.spdx.storage.IModelStore.IdType; + + +/** + * Generates a package verification code from a directory of source code or an array of SPDXFiles. + * + * A class implementing the IFileChecksumGenerator is supplied as a parameter to the constructor. + * The method getFileChecksum is called for each file in the directory. This can + * be used as a hook to capture all files in the directory and capture the checksum values at + * a file level. + * + * @author Gary O'Neall + * + */ +public class VerificationCodeGenerator { + + private IFileChecksumGenerator fileChecksumGenerator; + + public VerificationCodeGenerator(IFileChecksumGenerator fileChecksumGenerator) { + this.fileChecksumGenerator = fileChecksumGenerator; + } + + /** + * Generate the SPDX Package Verification Code from an array of SPDXFiles + * @param spdxFiles Files to generate the VerificationCode from + * @param skippedFilePaths File path names to not include in the VerificationCode + * @param modelStore where the resultant VerificationCode is store + * @param documentUri document URI where the VerificationCode is stored + * @return VerificationCode based on all files in spdxFiles minus the skippedFilePaths + * @throws NoSuchAlgorithmException + * @throws InvalidSPDXAnalysisException + */ + public SpdxPackageVerificationCode generatePackageVerificationCode(SpdxFile[] spdxFiles, + String[] skippedFilePaths, IModelStore modelStore, String documentUri) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException { + if (spdxFiles == null) { + return null; + } + Set skippedFilePathSet = new TreeSet<>(); + if (skippedFilePaths != null) { + for (int i = 0; i < skippedFilePaths.length; i++) { + if (skippedFilePaths[i] != null) { + skippedFilePathSet.add(skippedFilePaths[i]); + } + } + } + List fileChecksums = new ArrayList<>(); + for (int i = 0; i < spdxFiles.length; i++) { + if (spdxFiles[i] != null && spdxFiles[i].getName() != null && + !skippedFilePathSet.contains(spdxFiles[i].getName())) { + fileChecksums.add(spdxFiles[i].getSha1()); + } + } + return generatePackageVerificationCode(fileChecksums, skippedFilePaths, modelStore, documentUri); + } + + + /** + * Generate the SPDX Package Verification Code from a directory of files included in the archive + * @param sourceDirectory + * @param modelStore where the resultant VerificationCode is store + * @param documentUri document URI where the VerificationCode is stored + * @return PackageVerificationCode based on the files in the sourceDirectory + * @throws NoSuchAlgorithmException + * @throws IOException + * @throws InvalidSPDXAnalysisException + */ + public SpdxPackageVerificationCode generatePackageVerificationCode(File sourceDirectory, + File[] skippedFiles, IModelStore modelStore, String documentUri) throws NoSuchAlgorithmException, IOException, InvalidSPDXAnalysisException { + // create a sorted list of file paths + Set skippedFilesPath = new TreeSet<>(); + String rootOfDirectory = sourceDirectory.getAbsolutePath(); + int rootLen = rootOfDirectory.length()+1; + for (int i = 0; i < skippedFiles.length; i++) { + String skippedPath = normalizeFilePath(skippedFiles[i].getAbsolutePath().substring(rootLen)); + skippedFilesPath.add(skippedPath); + } + List fileChecksums = new ArrayList<>(); + collectFileData(rootOfDirectory, sourceDirectory, fileChecksums, skippedFilesPath); + String[] skippedFileNames = new String[skippedFilesPath.size()]; + Iterator iter = skippedFilesPath.iterator(); + int i = 0; + while (iter.hasNext()) { + skippedFileNames[i++] = iter.next(); + } + return generatePackageVerificationCode(fileChecksums, skippedFileNames, modelStore, documentUri); + } + + /** + * @param fileChecksums used to create the verification code value + * @param skippedFilePaths list of files skipped when calculating the verification code + * @param modelStore where the resultant VerificationCode is store + * @param documentUri document URI where the VerificationCode is stored + * @return a PackageVerificationCode with the value created from the fileChecksums + * @throws NoSuchAlgorithmException + * @throws InvalidSPDXAnalysisException + */ + protected SpdxPackageVerificationCode generatePackageVerificationCode(List fileChecksums, + String[] skippedFilePaths, IModelStore modelStore, String documentUri) throws NoSuchAlgorithmException, InvalidSPDXAnalysisException { + Collections.sort(fileChecksums); + MessageDigest verificationCodeDigest = MessageDigest.getInstance("SHA-1"); + for (int i = 0;i < fileChecksums.size(); i++) { + byte[] hashInput = fileChecksums.get(i).getBytes(Charset.forName("UTF-8")); + verificationCodeDigest.update(hashInput); + } + String value = convertChecksumToString(verificationCodeDigest.digest()); + SpdxPackageVerificationCode retval = new SpdxPackageVerificationCode(modelStore, documentUri, modelStore.getNextId(IdType.Anonymous, documentUri), null, true); + retval.setValue(value); + for (String skippedPath:skippedFilePaths) { + retval.getExcludedFileNames().add(skippedPath); + } + return retval; + } + + /** + * Collect the file level checksums and filenames + * @param prefixForRelative The portion of the filepath which preceeds the relative file path for the archive + * @param sourceDirectory + * @param fileNameAndChecksums + * @throws IOException + */ + private void collectFileData(String prefixForRelative, File sourceDirectory, + List fileNameAndChecksums, Set skippedFiles) throws IOException { + if (!sourceDirectory.isDirectory()) { + return; + } + File[] filesAndDirs = sourceDirectory.listFiles(); + if (filesAndDirs == null) { + return; + } + for (int i = 0; i < filesAndDirs.length; i++) { + if (filesAndDirs[i].isDirectory()) { + collectFileData(prefixForRelative, filesAndDirs[i], fileNameAndChecksums, skippedFiles); + } else { + String filePath = normalizeFilePath(filesAndDirs[i].getAbsolutePath() + .substring(prefixForRelative.length()+1)); + if (!skippedFiles.contains(filePath)) { + String checksumValue = this.fileChecksumGenerator.getFileChecksum(filesAndDirs[i]).toLowerCase(); + fileNameAndChecksums.add(checksumValue); + } + } + } + } + + /** + * Normalizes a file path per the SPDX spec + * @param nonNormalizedFilePath + * @return + */ + public static String normalizeFilePath(String nonNormalizedFilePath) { + String filePath = nonNormalizedFilePath.replace('\\', '/').trim(); + if (filePath.contains("../")) { + // need to remove these references + String[] filePathParts = filePath.split("/"); + StringBuilder normalizedFilePath = new StringBuilder(); + for (int j = 0; j < filePathParts.length; j++) { + if (j+1 < filePathParts.length && filePathParts[j+1].equals("..")) { + // skip this directory + } else if (filePathParts[j].equals("..")) { + // remove these from the filePath + } else { + if (j > 0) { + normalizedFilePath.append('/'); + } + normalizedFilePath.append(filePathParts[j]); + } + } + filePath = normalizedFilePath.toString(); + } + filePath = filePath.replace("./", ""); + if (!filePath.isEmpty() && filePath.charAt(0) == '/') { + filePath = "." + filePath; + } else { + filePath = "./" + filePath; + } + return filePath; + } + /** + * Convert a byte array SHA-1 digest into a 40 character hex string + * @param digest + * @return + */ + private static String convertChecksumToString(byte[] digest) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < digest.length; i++) { + String hex = Integer.toHexString(0xff & digest[i]); + if (hex.length() < 2) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } + /** + * @param sourceDirectory + * @param skippedFiles + * @param modelStore where the resultant VerificationCode is store + * @param documentUri document URI where the VerificationCode is stored + * @return + * @throws NoSuchAlgorithmException + * @throws IOException + * @throws InvalidSPDXAnalysisException + */ + public SpdxPackageVerificationCode generatePackageVerificationCode( + File sourceDirectory, IModelStore modelStore, String documentUri) throws NoSuchAlgorithmException, IOException, InvalidSPDXAnalysisException { + return generatePackageVerificationCode(sourceDirectory, new File[0], modelStore, documentUri); + } +} diff --git a/src/main/java/org/spdx/utility/verificationcode/package-info.java b/src/main/java/org/spdx/utility/verificationcode/package-info.java new file mode 100644 index 000000000..bb3924484 --- /dev/null +++ b/src/main/java/org/spdx/utility/verificationcode/package-info.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2020 Source Auditor Inc. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ +/** + * @author Gary O'Neall + * + * Classes used to generate PackageVerificationCodes + * + */ +package org.spdx.utility.verificationcode; \ No newline at end of file diff --git a/src/test/java/org/spdx/utility/verificationcode/VerificationCodeGeneratorTest.java b/src/test/java/org/spdx/utility/verificationcode/VerificationCodeGeneratorTest.java new file mode 100644 index 000000000..b8e2c8281 --- /dev/null +++ b/src/test/java/org/spdx/utility/verificationcode/VerificationCodeGeneratorTest.java @@ -0,0 +1,121 @@ +package org.spdx.utility.verificationcode; + + +import java.io.File; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.Collection; + +import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.library.model.SpdxFile; +import org.spdx.library.model.SpdxPackageVerificationCode; +import org.spdx.library.model.enumerations.ChecksumAlgorithm; +import org.spdx.library.model.enumerations.FileType; +import org.spdx.library.model.license.SpdxNoAssertionLicense; +import org.spdx.storage.IModelStore; +import org.spdx.storage.IModelStore.IdType; +import org.spdx.storage.simple.InMemSpdxStore; + +import junit.framework.TestCase; + +public class VerificationCodeGeneratorTest extends TestCase { + + static final String SOURCE_PATH = "TestFiles" + File.separator + "spdx-parser-source"; + + static final String[] SKIPPED_FILE_NAMES = new String[] { + "TestFiles" + File.separator + "spdx-parser-source" + File.separator + "org" + File.separator + "spdx" + File.separator + "rdfparser" + + File.separator + "DOAPProject.java", + "TestFiles" + File.separator + "spdx-parser-source" + File.separator + "org" + File.separator + "spdx" + File.separator + "rdfparser" + + File.separator + "SPDXFile.java" + }; + + private static final String SHA1_RESULT = "73e91925b5d50b9cc03d4da79f6ad9defcf63de3"; + + private static String[] SPDX_FILE_NAMES = new String[] { + "file/path/abc-not-skipped.java", "file/path/skipped.spdx", "file/path/not-skipped" + }; + + private static String[] SPDX_FILE_SHA1S = new String[] { + "dddd9215216045864ca5785d1892a00106cf0f6a", + "bbbb9215216045864ca5785d1892a00106cf0f6a", + "cccc9215216045864ca5785d1892a00106cf0f6a" + }; + + private SpdxFile[] SPDX_FILES; + + private IModelStore modelStore; + private static String DOCUMENT_URI = "https://TEST/DOCUMENT/URI"; + + protected void setUp() throws Exception { + super.setUp(); + modelStore = new InMemSpdxStore(); + SPDX_FILES = new SpdxFile[SPDX_FILE_NAMES.length]; + for (int i = 0; i < SPDX_FILES.length; i++) { + SPDX_FILES[i] = new SpdxFile(modelStore, DOCUMENT_URI, modelStore.getNextId(IdType.Anonymous, DOCUMENT_URI), null, true); + SPDX_FILES[i].setName(SPDX_FILE_NAMES[i]); + SPDX_FILES[i].getFileTypes().add(FileType.SOURCE); + SPDX_FILES[i].getChecksums().add(SPDX_FILES[i].createChecksum(ChecksumAlgorithm.SHA1, SPDX_FILE_SHA1S[i])); + SPDX_FILES[i].setLicenseConcluded(new SpdxNoAssertionLicense()); + SPDX_FILES[i].getLicenseInfoFromFiles().add(new SpdxNoAssertionLicense()); + } + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testGeneratePackageVerificationCodeFileFileArray() throws NoSuchAlgorithmException, IOException, InvalidSPDXAnalysisException { + VerificationCodeGenerator vg = new VerificationCodeGenerator(new JavaSha1ChecksumGenerator()); + File sourceDirectory = new File(SOURCE_PATH); + File[] skippedFiles = new File[SKIPPED_FILE_NAMES.length]; + for (int i = 0; i < skippedFiles.length; i++) { + skippedFiles[i] = new File(SKIPPED_FILE_NAMES[i]); + } + SpdxPackageVerificationCode vc = vg.generatePackageVerificationCode(sourceDirectory, skippedFiles, modelStore, DOCUMENT_URI); + assertEquals(SHA1_RESULT, vc.getValue()); + compareFileNameArrays(SKIPPED_FILE_NAMES, vc.getExcludedFileNames()); + } + + /** + * @param skippedFileNames + * @param excludedFileNames + */ + private void compareFileNameArrays(String[] skippedFileNames, + Collection excludedFileNames) { + assertEquals(skippedFileNames.length, excludedFileNames.size()); + for (String skippedFileName : skippedFileNames) { + boolean found = false; + String skippedFile = VerificationCodeGenerator.normalizeFilePath(skippedFileName.substring(SOURCE_PATH.length() + 1)); + for (String excludedFileName : excludedFileNames) { + if (excludedFileName.equals(skippedFile)) { + found = true; + break; + } + } + if (!found) { + fail(skippedFile + " not found"); + } + } + } + + public void testNormalizeFilePath() { + String s1 = "simple/test.c"; + String ns1 = "./simple/test.c"; + String s2 = "name"; + String ns2 = "./name"; + String s3 = "dos\\file\\name.c"; + String ns3 = "./dos/file/name.c"; + String s4 = "\\leading\\slash"; + String ns4 = "./leading/slash"; + String s5 = "test/./dot/./slash"; + String ns5 = "./test/dot/slash"; + String s6 = "test/parent/../directory/name"; + String ns6 = "./test/directory/name"; + assertEquals(ns1, VerificationCodeGenerator.normalizeFilePath(s1)); + assertEquals(ns2, VerificationCodeGenerator.normalizeFilePath(s2)); + assertEquals(ns3, VerificationCodeGenerator.normalizeFilePath(s3)); + assertEquals(ns4, VerificationCodeGenerator.normalizeFilePath(s4)); + assertEquals(ns5, VerificationCodeGenerator.normalizeFilePath(s5)); + assertEquals(ns6, VerificationCodeGenerator.normalizeFilePath(s6)); + } +} From 8fd921f48aa350bb23f3776d0974fbcdb370d08d Mon Sep 17 00:00:00 2001 From: Gary O'Neall Date: Mon, 5 Oct 2020 18:41:32 -0700 Subject: [PATCH 6/6] Fix JavaDocs configuration Signed-off-by: Gary O'Neall --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0322195c0..8c3ed190a 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ true 8 - ${java.home}/bin/javadoc + ${env.JAVA_HOME}/bin/javadoc -Xdoclint:none