ontPropEntry:sortedOntProperties.entrySet()) {
93 | String propNamespace = uriToNamespace(ontPropEntry.getValue().getURI());
94 | String propName = uriToPropName(ontPropEntry.getValue().getURI());
95 |
96 | PropertyRestrictions propertyRestrictions = new PropertyRestrictions(ontPropEntry.getValue());
97 | boolean hasListProperty = propertyRestrictions.isListProperty();
98 | String typeUri = propertyRestrictions.getTypeUri();
99 | if (hasListProperty) {
100 | String listPropName = MultiFormatStore.propertyNameToCollectionPropertyName(propName);
101 | ObjectNode listPropContext = JSON_MAPPER.createObjectNode();
102 | listPropContext.put("@id", propNamespace + listPropName);
103 | if (Objects.nonNull(typeUri)) {
104 | listPropContext.put("@type", uriToNamespace(typeUri) + uriToPropName(typeUri));
105 | }
106 | listPropContext.put("@container", "@set");
107 | contexts.set(listPropName, listPropContext);
108 | } if (propertyRestrictions.isSingleProperty()) {
109 | ObjectNode propContext = JSON_MAPPER.createObjectNode();
110 | propContext.put("@id", ontPropEntry.getKey());
111 | if (Objects.nonNull(typeUri)) {
112 | propContext.put("@type", uriToNamespace(typeUri) + uriToPropName(typeUri));
113 | }
114 | contexts.set(propName, propContext);
115 | }
116 | }
117 | ObjectNode context = JSON_MAPPER.createObjectNode();
118 | context.set("@context", contexts);
119 | return context;
120 | }
121 |
122 |
123 | /**
124 | * @param uri
125 | * @return The namespace portion of the URI
126 | */
127 | private String uriToNamespace(String uri) {
128 | int poundIndex = uri.lastIndexOf('#');
129 | String propNamespace = uri.substring(0, poundIndex+1);
130 | if (NAMESPACES.containsKey(propNamespace)) {
131 | propNamespace = NAMESPACES.get(propNamespace) + ":";
132 | }
133 | return propNamespace;
134 | }
135 |
136 | /**
137 | * @param uri
138 | * @return The name portion of the URI
139 | */
140 | private String uriToPropName(String uri) {
141 | int poundIndex = uri.lastIndexOf('#');
142 | return checkConvertRenamedPropertyName(uri.substring(poundIndex+1));
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/examples/org/spdx/examples/ExistingSpdxDocumentV2Compat.java:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: Copyright (c) 2021 Source Auditor Inc.
3 | * SPDX-FileType: SOURCE
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 | package org.spdx.examples;
7 |
8 | import java.io.File;
9 | import java.io.FileInputStream;
10 | import java.io.FileNotFoundException;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.util.Collection;
14 | import java.util.List;
15 | import java.util.stream.Collectors;
16 |
17 | import org.spdx.jacksonstore.MultiFormatStore;
18 | import org.spdx.jacksonstore.MultiFormatStore.Format;
19 | import org.spdx.core.InvalidSPDXAnalysisException;
20 | import org.spdx.library.ModelCopyManager;
21 | import org.spdx.library.SpdxModelFactory;
22 | import org.spdx.library.model.v2.SpdxConstantsCompatV2;
23 | import org.spdx.library.model.v2.SpdxDocument;
24 | import org.spdx.library.model.v2.SpdxElement;
25 | import org.spdx.storage.ISerializableModelStore;
26 | import org.spdx.storage.simple.InMemSpdxStore;
27 |
28 | /**
29 | * This example demonstrate opening an existing SPDX spec version 2.X document and accessing it. The format
30 | * for this example is assumed to be JSON (e.g. the output of the SimpleSpdxDocumentV2Compat example).
31 | * Different format can be used by using the associated store rather than the spdx-jackson store
32 | * (e.g. spdx-spreadsheet-store, spdx-tagvalue-store, or the spdx-rdf-store).
33 | *
34 | * This example depends on the Spdx-Java-Library and the spdx-java-jackson store libraries
35 | *
36 | * @author Gary O'Neall
37 | */
38 | public class ExistingSpdxDocumentV2Compat {
39 |
40 | /**
41 | * @param args args[0] is the file path containing the SPDX document
42 | */
43 | public static void main(String[] args) {
44 | if (args.length != 1) {
45 | usage();
46 | System.exit(1);
47 | }
48 | File inputFile = new File(args[0]);
49 | if (!inputFile.exists()) {
50 | System.out.println("Input file does not exist: "+args[0]);
51 | System.exit(1);
52 | }
53 |
54 | /*
55 | * First thing we need is a store deserialize the SPDX document into.
56 | * We'll chose the MultiFormatStore since it supports serializing to JSON files
57 | * It takes an underlying model store as the first parameter - the inMemSpdxStore is a simple
58 | * built in store included in the Spdx-Java-Library. The second parameter is the format
59 | * to use when serializing or deserializing
60 | */
61 | ISerializableModelStore modelStore = new MultiFormatStore(new InMemSpdxStore(), Format.JSON_PRETTY);
62 | /*
63 | * There are several other choices which can be made for a model store - most of which
64 | * are in separate libraries that need to be included as dependencies. Below are a few examples:
65 | * IModelStore modelStore = new InMemSpdxStore(); - the simplest store, but does not support serializing or deserializing
66 | * ISerializableModelStore modelStore = new TagValueStore(new InMemSpdxStore()); Supports serializing and deserializing SPDX tag/value files
67 | * ISerializableModelStore modelStore = new RdfStore(); Supports serializing and deserializing various RDF formats (e.g. RDF/XML, RDF/Turtle)
68 | * ISerializableModelStore modelStore = new SpreadsheetStore(new InMemSpdxStore()); Supports serializing and deserializing .XLS or .XLSX spreadsheets
69 | */
70 |
71 | /*
72 | * The ModelCopyManager is used when using more than one Model Store. The Listed Licenses uses
73 | * it's own model store, so we will need a ModelCopyManager to manage the copying of the listed
74 | * license information over to the document model store
75 | */
76 | ModelCopyManager copyManager = new ModelCopyManager();
77 | // Let's deserialize the document
78 | try (InputStream stream = new FileInputStream(inputFile)) {
79 | modelStore.deSerialize(stream, false);
80 |
81 | } catch (FileNotFoundException e1) {
82 | System.out.println("Input file does not exist: "+args[0]);
83 | System.exit(1);
84 | } catch (IOException e1) {
85 | System.out.println("I/O error reading input file: "+args[0]);
86 | System.exit(1);
87 | } catch (InvalidSPDXAnalysisException e) {
88 | System.out.println("The SPDX document is not valid: "+e.getMessage());
89 | System.exit(1);
90 | }
91 | // Now that the document is deserialized, we can access it using the SpdxModelFactory
92 | try {
93 | // To find all the SPDX documents in the model store, use the getObjects method from the
94 | // SpdxModelFactory passing in the SpdxDocument type
95 | // When using the factory method, we have to type cast the result
96 | @SuppressWarnings("unchecked")
97 | List allDocs = (List) SpdxModelFactory.getSpdxObjects(modelStore, copyManager,
98 | SpdxConstantsCompatV2.CLASS_SPDX_DOCUMENT, null, null)
99 | .collect(Collectors.toList());
100 | SpdxDocument document = allDocs.get(0);
101 | String documentUri = document.getDocumentUri();
102 | // If you know the document URI, you can simply create an SPDX document using the followint constructor
103 | SpdxDocument document2 = new SpdxDocument(modelStore, documentUri, copyManager, false);
104 | // Note that all class objects in the Spdx Java Library follow the same pattern -
105 | // to access any existing object in the store, simply create the object passing in
106 | // the document URI, model store and the ID for the object
107 | // Since the 2 documents are just references to the same object, they will always be equivalent
108 | if (!document.equivalent(document2)) {
109 | System.out.println("Oops - these 2 documents should be the same");
110 | System.exit(1);
111 | }
112 | // Let's see find what the document is describing
113 | Collection described = document.getDocumentDescribes();
114 | for (SpdxElement des:described) {
115 | System.out.println("The document described ID "+des.getId());
116 | }
117 | System.exit(0);
118 | } catch (InvalidSPDXAnalysisException e) {
119 | System.out.println("Unexpected error reading SPDX document: "+e.getMessage());
120 | System.exit(1);
121 | }
122 | }
123 |
124 | private static void usage() {
125 | System.out.println("Usage: ExistingSpxDocument inputFilePath");
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SPDX Tools
2 |
3 | [](https://central.sonatype.com/artifact/org.spdx/tools-java)
4 | [](https://javadoc.io/doc/org.spdx/tools-java)
5 |
6 | A command-line utility for creating, converting, comparing,
7 | and validating SPDX documents across multiple formats.
8 |
9 | The Software Package Data Exchange (SPDX) specification is a standard format for communicating the components, licenses and copyrights associated with a software package.
10 |
11 | * [SPDX License List](https://spdx.org/licenses/)
12 | * [SPDX Vocabulary Specification](https://spdx.org/specifications)
13 |
14 | These tools are published by the SPDX Workgroup,
15 | see
16 |
17 | ## Versions Supported
18 |
19 | This utility supports versions 2.0, 2.1, 2.2, 2.3 and 3.0.1 of the SPDX specification.
20 |
21 | ## Code quality badges
22 |
23 | [](https://sonarcloud.io/dashboard?id=tools-java)
24 | [](https://sonarcloud.io/dashboard?id=tools-java)
25 | [](https://sonarcloud.io/dashboard?id=tools-java)
26 | [](https://sonarcloud.io/dashboard?id=tools-java)
27 |
28 | ## Getting Starting
29 |
30 | The SPDX Tools binaries can be downloaded from the [releases page](https://github.com/spdx/tools-java/releases) under the respective release. The package is also available in [Maven Central](https://central.sonatype.com/artifact/org.spdx/tools-java) (organization `org.spdx`, artifact `tools-java`).
31 |
32 | See the Syntax section below for the commands available.
33 |
34 | If you are a developer, there are examples in the [examples folder](examples/org/spdx/examples).
35 |
36 | ## Syntax
37 |
38 | The command line interface of the SPDX Tools can be used like this:
39 |
40 | java -jar tools-java-2.0.2-jar-with-dependencies.jar
41 |
42 | ## SPDX format converters
43 |
44 | The following converter tools support SPDX format:
45 |
46 | * Tag
47 | * RDF/XML
48 | * XLSX Spreadsheet
49 | * XLS Spreadsheet
50 | * JSON
51 | * XML
52 | * YAML
53 | * JSON-LD (SPDX spec version 3.0.1)
54 |
55 | Example to convert a SPDX file from Tag to RDF format:
56 |
57 | java -jar tools-java-2.0.2-jar-with-dependencies.jar Convert ../testResources/SPDXTagExample-v2.2.spdx TagToRDF.rdf
58 |
59 | The file formats can optionally be provided as the 3rd and 4th parameter for the input and output formats respectively. An optional 5th option `excludeLicenseDetails` will not copy the listed license properties to the output file. The following example will copy a JSON format to an RDF Turtle format without including the listed license properties:
60 |
61 | java -jar tools-java-2.0.2-jar-with-dependencies.jar Convert ../testResources/SPDXTagExample-v2.2.spdx TagToRDF.ttl TAG RDFTTL excludeLicenseDetails
62 |
63 | To convert from SPDX 2 to SPDX 3.0.1:
64 |
65 | * use the file extension `.jsonld.json` or `.jsonld`;
66 | * or add the options for the from and to file types:
67 |
68 | java -jar tools-java-2.0.2-jar-with-dependencies.jar Convert hello.spdx hello.spdx.json TAG JSONLD
69 |
70 | ## Compare utilities
71 |
72 | The following tools can be used to compare one or more SPDX documents:
73 |
74 | * CompareMultipleSpdxDocs with files
75 |
76 | Example to compare multiple SPDX files provided in RDF format and provide a spreadsheet with the results:
77 |
78 | java -jar tools-java-2.0.2-jar-with-dependencies.jar CompareDocs output.xlsx doc1 doc2 ... docN
79 |
80 | * CompareMultipleSpdxDocs with directory
81 |
82 | Example to compare all SPDX documents in a directory "/home/me/spdxdocs" and provide a spreadsheet with the results:
83 |
84 | java -jar tools-java-2.0.2-jar-with-dependencies.jar CompareDocs output.xlsx /home/me/spdxdocs
85 |
86 | ## SPDX Viewer
87 |
88 | The following tool can be used to "Pretty Print" an SPDX document.
89 |
90 | * SPDXViewer
91 |
92 | Sample usage:
93 |
94 | java -jar tools-java-2.0.2-jar-with-dependencies.jar SPDXViewer ../testResources/SPDXRdfExample-v2.2.spdx.rdf
95 |
96 | ## Verifier
97 |
98 | The following tool can be used to verify an SPDX document:
99 |
100 | * Verify
101 |
102 | Sample usage:
103 |
104 | java -jar tools-java-2.0.2-jar-with-dependencies.jar Verify ../testResources/SPDXRdfExample-v2.2.spdx.rdf
105 |
106 | ## Generators
107 |
108 | The following tool can be used to generate an SPDX verification code from a directory of source files:
109 |
110 | * GenerateVerificationCode sourceDirectory
111 |
112 | Sample usage:
113 |
114 | java -jar tools-java-2.0.2-jar-with-dependencies.jar GenerateVerificationCode sourceDirectory [ignoredFilesRegex]
115 |
116 | ## SPDX Validation Tool
117 |
118 | The SPDX Workgroup provides an online interface to validate, compare, and convert SPDX documents in addition to the command line options above.
119 |
120 | The [SPDX Online Tools](https://tools.spdx.org/) is an all-in-one portal to upload and parse SPDX documents for validation, comparison and conversion and search the SPDX license list.
121 |
122 | ## License
123 |
124 | A complete SPDX file is available including dependencies is available in the bintray and Maven repos.
125 |
126 | SPDX-License-Identifier: Apache-2.0
127 | PackageLicenseDeclared: Apache-2.0
128 |
129 | ## Development
130 |
131 | ### Build
132 |
133 | You need [Apache Maven](http://maven.apache.org/) to build the project:
134 |
135 | mvn clean install
136 |
137 | ## Contributing
138 |
139 | See the file [CONTRIBUTING.md](./CONTRIBUTING.md) for information on
140 | making contributions to the SPDX tools.
141 |
142 | ## Issues
143 |
144 | Report any security related issues by sending an email to [spdx-tools-security@lists.spdx.org](mailto:spdx-tools-security@lists.spdx.org)
145 |
146 | Non-security related issues should be added to the [SPDX Tools issues list](https://github.com/spdx/tools-java/issues)
147 |
--------------------------------------------------------------------------------
/src/main/java/org/spdx/tools/GenerateVerificationCode.java:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: Copyright (c) 2011 Source Auditor Inc.
3 | * SPDX-FileType: SOURCE
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 | package org.spdx.tools;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.security.NoSuchAlgorithmException;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 | import java.util.Objects;
27 | import java.util.regex.Pattern;
28 |
29 | import javax.annotation.Nullable;
30 |
31 | import org.spdx.core.InvalidSPDXAnalysisException;
32 | import org.spdx.library.model.v2.SpdxPackageVerificationCode;
33 | import org.spdx.storage.IModelStore;
34 | import org.spdx.storage.simple.InMemSpdxStore;
35 | import org.spdx.utility.verificationcode.JavaSha1ChecksumGenerator;
36 | import org.spdx.utility.verificationcode.VerificationCodeGenerator;
37 |
38 | /**
39 | * Generates a verification code for a specific directory
40 | * @author Gary O'Neall
41 | */
42 | public class GenerateVerificationCode {
43 |
44 | /**
45 | * Print an SPDX Verification code for a directory of files
46 | * args[0] is the source directory containing the files
47 | * args[1] is an optional regular expression of skipped files. The expression is applied against a file path relative the the source directory supplied
48 | * @param args
49 | */
50 | public static void main(String[] args) {
51 | if (args.length < 1 || args.length > 2) {
52 | error("Incorrect number of arguments.");
53 | System.exit(1);
54 | }
55 | String directoryPath = args[0];
56 | String skippedRegex = null;
57 | if (args.length > 1) {
58 | skippedRegex = args[1];
59 | }
60 |
61 | SpdxToolsHelper.initialize();
62 | try {
63 | SpdxPackageVerificationCode verificationCode = generateVerificationCode(directoryPath, skippedRegex);
64 | printVerificationCode(verificationCode);
65 | System.exit(0);
66 | } catch (Exception ex) {
67 | error("Error creating verification code: "+ex.getMessage());
68 | System.exit(1);
69 | }
70 | }
71 |
72 | public static SpdxPackageVerificationCode generateVerificationCode(String directoryPath, @Nullable String skippedRegex) throws OnlineToolException {
73 | Objects.requireNonNull(directoryPath, "Directory path must not be null");
74 | File sourceDirectory = new File(directoryPath);
75 | if (!sourceDirectory.exists()) {
76 | throw new OnlineToolException("Source directory "+directoryPath+" does not exist.");
77 | }
78 | if (!sourceDirectory.isDirectory()) {
79 | throw new OnlineToolException("File "+directoryPath+" is not a directory.");
80 | }
81 | File[] skippedFiles = new File[0];
82 | if (Objects.nonNull(skippedRegex)) {
83 | skippedFiles = collectSkippedFiles(skippedRegex, sourceDirectory);
84 | }
85 | try {
86 | VerificationCodeGenerator vcg = new VerificationCodeGenerator(new JavaSha1ChecksumGenerator());
87 | IModelStore ms = new InMemSpdxStore();
88 | return vcg.generatePackageVerificationCode(sourceDirectory, skippedFiles, ms, "https://temp/URI");
89 | } catch (NoSuchAlgorithmException e) {
90 | throw new OnlineToolException("Error creating checksum algorithm",e);
91 | } catch (IOException e) {
92 | throw new OnlineToolException("I/O Error generating verification code",e);
93 | } catch (InvalidSPDXAnalysisException e) {
94 | throw new OnlineToolException("SPDX Analysis Error generating verification code",e);
95 | }
96 | }
97 |
98 | /**
99 | * Collect files to be skipped
100 | * @param skippedRegex Regular Expression for file paths to be skipped
101 | * @param dir Directory to scan for collecting skipped files
102 | * @return
103 | */
104 | private static File[] collectSkippedFiles(String skippedRegex, File dir) {
105 | Pattern skippedPattern = Pattern.compile(skippedRegex);
106 | List skippedFiles = new ArrayList<>();
107 | collectSkippedFiles(skippedPattern, skippedFiles, dir.getPath(), dir);
108 | File[] retval = new File[skippedFiles.size()];
109 | retval = skippedFiles.toArray(retval);
110 | return retval;
111 | }
112 |
113 | /**
114 | * Internal method to recurse through the source directory collecting files to skip
115 | * @param skippedPattern
116 | * @param skippedFiles
117 | * @param rootPath
118 | * @param dir
119 | * @return
120 | */
121 | private static void collectSkippedFiles(Pattern skippedPattern,
122 | List skippedFiles, String rootPath, File dir) {
123 | if (dir.isFile()) {
124 | String relativePath = dir.getPath().substring(rootPath.length()+1);
125 | if (skippedPattern.matcher(relativePath).matches()) {
126 | skippedFiles.add(dir);
127 | }
128 | } else if (dir.isDirectory()) {
129 | File[] children = dir.listFiles();
130 | if (children != null) {
131 | for (int i = 0; i < children.length; i++) {
132 | if (children[i].isFile()) {
133 | String relativePath = children[i].getPath().substring(rootPath.length()+1);
134 | if (skippedPattern.matcher(relativePath).matches()) {
135 | skippedFiles.add(children[i]);
136 | }
137 | } else if (children[i].isDirectory()) {
138 | collectSkippedFiles(skippedPattern, skippedFiles, rootPath, children[i]);
139 | }
140 | }
141 | }
142 | }
143 | }
144 |
145 | /**
146 | * @param verificationCode
147 | * @throws InvalidSPDXAnalysisException
148 | */
149 | private static void printVerificationCode(
150 | SpdxPackageVerificationCode verificationCode) throws InvalidSPDXAnalysisException {
151 | System.out.println("Verification code value: "+verificationCode.getValue());
152 | String[] excludedFiles = verificationCode.getExcludedFileNames().toArray(new String[verificationCode.getExcludedFileNames().size()]);
153 | if (excludedFiles != null && excludedFiles.length > 0) {
154 | System.out.println("Excluded files:");
155 | for (int i = 0; i < excludedFiles.length; i++) {
156 | System.out.println("\t"+excludedFiles[i]);
157 | }
158 | } else {
159 | System.out.println("No excluded files");
160 | }
161 | }
162 |
163 | /**
164 | * @param string
165 | */
166 | private static void error(String string) {
167 | System.out.println(string);
168 | usage();
169 | }
170 |
171 | /**
172 | *
173 | */
174 | private static void usage() {
175 | System.out.println("Usage: GenerateVerificationCode sourceDirectory [skippedFiles]");
176 | System.out.println("where sourceDirectory is the root of the archive file for which the verification code is generated and [skippedFiles] is an optional regular expression of skipped files. The expression is applied against a file path relative the the source directory supplied");
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/src/test/java/org/spdx/tools/CompareSpdxDocsTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: Copyright (c) 2020 Source Auditor Inc.
3 | * SPDX-FileType: SOURCE
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 | package org.spdx.tools;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.nio.file.Files;
24 | import java.nio.file.Path;
25 | import java.util.Objects;
26 |
27 | import org.apache.poi.ss.usermodel.Cell;
28 | import org.apache.poi.ss.usermodel.Row;
29 | import org.spdx.core.DefaultModelStore;
30 | import org.spdx.core.InvalidSPDXAnalysisException;
31 | import org.spdx.core.ModelRegistry;
32 | import org.spdx.library.ModelCopyManager;
33 | import org.spdx.library.model.v2.SpdxModelInfoV2_X;
34 | import org.spdx.library.model.v3_0_1.SpdxModelInfoV3_0;
35 | import org.spdx.spreadsheetstore.SpreadsheetException;
36 | import org.spdx.storage.simple.InMemSpdxStore;
37 | import org.spdx.tools.compare.DocumentSheet;
38 | import org.spdx.tools.compare.MultiDocumentSpreadsheet;
39 |
40 | import junit.framework.TestCase;
41 |
42 | /**
43 | * Test cases for CompareSpdxDocs
44 | *
45 | * @author Gary O'Neall
46 | */
47 | public class CompareSpdxDocsTest extends TestCase {
48 |
49 | static final String TEST_DIR = "testResources";
50 | static final String TEST_JSON_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXJSONExample-v2.2.spdx.json";
51 | static final String TEST_RDF_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXRdfExample-v2.2.spdx.rdf";
52 | static final String TEST_SPREADSHEET_XLS_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.2.xls";
53 | static final String TEST_SPREADSHEET_XLSX_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.2.xlsx";
54 | static final String TEST_TAG_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXTagExample-v2.2.spdx";
55 | static final String TEST_XML_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXXMLExample-v2.2.spdx.xml";
56 | static final String TEST_YAML_FILE_PATH_22 = TEST_DIR + File.separator + "SPDXYAMLExample-2.2.spdx.yaml";
57 |
58 | static final String TEST_JSON_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXJSONExample-v2.3.spdx.json";
59 | static final String TEST_RDF_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXRdfExample-v2.3.spdx.rdf";
60 | static final String TEST_SPREADSHEET_XLS_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xls";
61 | static final String TEST_SPREADSHEET_XLSX_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXSpreadsheetExample-v2.3.xlsx";
62 | static final String TEST_TAG_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXTagExample-v2.3.spdx";
63 | static final String TEST_XML_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXXMLExample-v2.3.spdx.xml";
64 | static final String TEST_YAML_FILE_PATH_23 = TEST_DIR + File.separator + "SPDXYAMLExample-2.3.spdx.yaml";
65 |
66 | static final String TEST_DIFF_FILE_COMMENT_FILE_PATH = TEST_DIR + File.separator + "DifferentFileComment.spdx.yaml";
67 |
68 |
69 |
70 | Path tempDirPath;
71 | /* (non-Javadoc)
72 | * @see junit.framework.TestCase#setUp()
73 | */
74 | protected void setUp() throws Exception {
75 | super.setUp();
76 | ModelRegistry.getModelRegistry().registerModel(new SpdxModelInfoV3_0());
77 | ModelRegistry.getModelRegistry().registerModel(new SpdxModelInfoV2_X());
78 | DefaultModelStore.initialize(new InMemSpdxStore(), "http://default/namespace", new ModelCopyManager());
79 | tempDirPath = Files.createTempDirectory("spdx-tools-test-");
80 | }
81 |
82 | /* (non-Javadoc)
83 | * @see junit.framework.TestCase#tearDown()
84 | */
85 | protected void tearDown() throws Exception {
86 | super.tearDown();
87 | SpdxConverterTestV2.deleteDirAndFiles(tempDirPath);
88 | }
89 |
90 | public void testCompareDocumentsv23() throws OnlineToolException, InvalidSPDXAnalysisException, IOException, InvalidFileNameException {
91 | String outputFilePath = tempDirPath + File.separator + "comp.xlsx";
92 | String[] params = new String[] {outputFilePath,
93 | TEST_JSON_FILE_PATH_23,
94 | TEST_RDF_FILE_PATH_23,
95 | TEST_SPREADSHEET_XLS_FILE_PATH_23,
96 | TEST_SPREADSHEET_XLSX_FILE_PATH_23,
97 | TEST_TAG_FILE_PATH_23,
98 | TEST_XML_FILE_PATH_23,
99 | TEST_YAML_FILE_PATH_23
100 | };
101 | CompareSpdxDocs.onlineFunction(params);
102 | MultiDocumentSpreadsheet result = new MultiDocumentSpreadsheet(new File(outputFilePath), false, true);
103 | DocumentSheet docSheet = result.getDocumentSheet();
104 | Row resultRow = docSheet.getSheet().getRow(docSheet.getFirstDataRow());
105 | Cell cell = resultRow.getCell(1);
106 | int nextCol = 2;
107 | while (Objects.nonNull(cell) && !cell.getStringCellValue().isEmpty()) {
108 | assertTrue("Equals".equals(cell.getStringCellValue()) || "N/A".equals(cell.getStringCellValue()));
109 | cell = resultRow.getCell(nextCol++);
110 | }
111 | }
112 |
113 | public void testCompareDocumentsv22() throws OnlineToolException, SpreadsheetException {
114 | String outputFilePath = tempDirPath + File.separator + "comp.xlsx";
115 | String[] params = new String[] {outputFilePath, TEST_JSON_FILE_PATH_22,
116 | TEST_RDF_FILE_PATH_22, TEST_SPREADSHEET_XLS_FILE_PATH_22,
117 | TEST_SPREADSHEET_XLSX_FILE_PATH_22, TEST_TAG_FILE_PATH_22,
118 | TEST_XML_FILE_PATH_22,
119 | TEST_YAML_FILE_PATH_22
120 | };
121 | CompareSpdxDocs.onlineFunction(params);
122 | MultiDocumentSpreadsheet result = new MultiDocumentSpreadsheet(new File(outputFilePath), false, true);
123 | DocumentSheet docSheet = result.getDocumentSheet();
124 | Row resultRow = docSheet.getSheet().getRow(docSheet.getFirstDataRow());
125 | Cell cell = resultRow.getCell(1);
126 | int nextCol = 2;
127 | while (Objects.nonNull(cell) && !cell.getStringCellValue().isEmpty()) {
128 | String cellResult = cell.getStringCellValue();
129 | assertTrue("Equals".equals(cell.getStringCellValue()) || "N/A".equals(cellResult));
130 | cell = resultRow.getCell(nextCol++);
131 | }
132 | }
133 |
134 |
135 | public void testDifferentDocuments() throws OnlineToolException, SpreadsheetException {
136 | String outputFilePath = tempDirPath + File.separator + "comp.xlsx";
137 | String[] params = new String[] {outputFilePath,
138 | TEST_YAML_FILE_PATH_22, TEST_DIFF_FILE_COMMENT_FILE_PATH
139 | };
140 | CompareSpdxDocs.onlineFunction(params);
141 | MultiDocumentSpreadsheet result = new MultiDocumentSpreadsheet(new File(outputFilePath), false, true);
142 | DocumentSheet docSheet = result.getDocumentSheet();
143 | Row resultRow = docSheet.getSheet().getRow(docSheet.getFirstDataRow());
144 | Row titleRow = docSheet.getSheet().getRow(docSheet.getFirstDataRow()-1);
145 | Cell cell = resultRow.getCell(1);
146 | int nextCol = 2;
147 | while (Objects.nonNull(cell) && !cell.getStringCellValue().isEmpty()) {
148 | if ("Document Describes".equals(titleRow.getCell(nextCol-1).getStringCellValue()) || "Relationships".equals(titleRow.getCell(nextCol-1).getStringCellValue())) {
149 | assertTrue("Diff".equals(cell.getStringCellValue()));
150 | } else {
151 | assertTrue("Equals".equals(cell.getStringCellValue()) || "N/A".equals(cell.getStringCellValue()));
152 | }
153 | cell = resultRow.getCell(nextCol++);
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/testResources/sourcefiles/DocumentRelationshipSheet.java:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: Copyright (c) 2015 Source Auditor Inc.
3 | * SPDX-FileType: SOURCE
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 | package org.spdx.tools.compare;
20 |
21 | import java.io.Serializable;
22 | import java.util.Arrays;
23 | import java.util.Comparator;
24 | import java.util.List;
25 |
26 | import org.apache.poi.ss.usermodel.Cell;
27 | import org.apache.poi.ss.usermodel.CellStyle;
28 | import org.apache.poi.ss.usermodel.Row;
29 | import org.apache.poi.ss.usermodel.Sheet;
30 | import org.apache.poi.ss.usermodel.Workbook;
31 | import org.spdx.library.InvalidSPDXAnalysisException;
32 | import org.spdx.library.model.Relationship;
33 | import org.spdx.utility.compare.SpdxCompareException;
34 | import org.spdx.utility.compare.SpdxComparer;
35 |
36 | /**
37 | * Sheet for document level relationships
38 | * @author Gary O'Neall
39 | */
40 | public class DocumentRelationshipSheet extends AbstractSheet {
41 |
42 | private static class RelationshipComparator implements Comparator, Serializable {
43 |
44 | /**
45 | * Default
46 | */
47 | private static final long serialVersionUID = 1L;
48 |
49 | /* (non-Javadoc)
50 | * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
51 | */
52 | @Override
53 | public int compare(Relationship o1, Relationship o2) {
54 | try {
55 | if (o1 != null) {
56 | if (o2 != null) {
57 | Relationship r1 = o1;
58 | Relationship r2 = o2;
59 | int retval = r1.getRelationshipType().toString().compareTo(r2.getRelationshipType().toString());
60 | if (retval != 0) {
61 | return retval;
62 | } else if (r1.getRelatedSpdxElement().isPresent() && !r2.getRelatedSpdxElement().isPresent()) {
63 | return 1;
64 | } else if (!r1.getRelatedSpdxElement().isPresent() && r2.getRelatedSpdxElement().isPresent()) {
65 | return -1;
66 | } else if (r1.getRelatedSpdxElement().get().equivalent(r2.getRelatedSpdxElement().get())) {
67 | return 0;
68 | } else if (r1.getRelatedSpdxElement().get().getName().isPresent() &&
69 | r2.getRelatedSpdxElement().get().getName().isPresent()) {
70 | return r1.getRelatedSpdxElement().get().getName().get().compareTo(
71 | r2.getRelatedSpdxElement().get().getName().get());
72 | } else {
73 | return r1.getRelatedSpdxElement().get().getId().compareTo(r2.getRelatedSpdxElement().get().getId());
74 | }
75 | } else {
76 | return 1;
77 | }
78 | } else {
79 | return -1;
80 | }
81 | } catch(InvalidSPDXAnalysisException ex) {
82 | logger.error("Error comparing relationships", ex);
83 | throw new RuntimeException(ex);
84 | }
85 |
86 | }
87 | }
88 |
89 | RelationshipComparator relationshipComparator = new RelationshipComparator();
90 |
91 | static final int TYPE_COL = 0;
92 | static final int TYPE_COL_WIDTH = 25;
93 | static final String TYPE_COL_TEXT_TITLE = "Type";
94 | static final int FIRST_RELATIONSHIP_COL = 1;
95 | static final int FIRST_RELATIONSHIP_COL_WIDTH = 60;
96 |
97 | public DocumentRelationshipSheet(Workbook workbook, String sheetName) {
98 | super(workbook, sheetName);
99 | }
100 |
101 | /**
102 | * @param wb
103 | * @param sheetName
104 | */
105 | public static void create(Workbook wb, String sheetName) {
106 | int sheetNum = wb.getSheetIndex(sheetName);
107 | if (sheetNum >= 0) {
108 | wb.removeSheetAt(sheetNum);
109 | }
110 | Sheet sheet = wb.createSheet(sheetName);
111 | CellStyle headerStyle = AbstractSheet.createHeaderStyle(wb);
112 | CellStyle defaultStyle = AbstractSheet.createLeftWrapStyle(wb);
113 | Row row = sheet.createRow(0);
114 |
115 | sheet.setColumnWidth(TYPE_COL, TYPE_COL_WIDTH*256);
116 | sheet.setDefaultColumnStyle(TYPE_COL, defaultStyle);
117 | Cell typeHeaderCell = row.createCell(TYPE_COL);
118 | typeHeaderCell.setCellStyle(headerStyle);
119 | typeHeaderCell.setCellValue(TYPE_COL_TEXT_TITLE);
120 |
121 | for (int i = FIRST_RELATIONSHIP_COL; i < MultiDocumentSpreadsheet.MAX_DOCUMENTS; i++) {
122 | sheet.setColumnWidth(i, FIRST_RELATIONSHIP_COL_WIDTH*256);
123 | sheet.setDefaultColumnStyle(i, defaultStyle);
124 | Cell cell = row.createCell(i);
125 | cell.setCellStyle(headerStyle);
126 | }
127 | }
128 |
129 | /**
130 | * @param comparer
131 | * @param docNames
132 | * @throws InvalidSPDXAnalysisException
133 | */
134 | public void importCompareResults(SpdxComparer comparer, List docNames) throws SpdxCompareException, InvalidSPDXAnalysisException {
135 | if (comparer.getNumSpdxDocs() != docNames.size()) {
136 | throw(new SpdxCompareException("Number of document names does not match the number of SPDX documents"));
137 | }
138 | this.clear();
139 | Row header = sheet.getRow(0);
140 | int[] relationshipsIndexes = new int[comparer.getNumSpdxDocs()];
141 | Relationship[][] relationships = new Relationship[comparer.getNumSpdxDocs()][];
142 | for (int i = 0; i < relationships.length; i++) {
143 | Cell headerCell = header.getCell(FIRST_RELATIONSHIP_COL+i);
144 | headerCell.setCellValue(docNames.get(i));
145 | Relationship[] docRelationships = comparer.getSpdxDoc(i).getRelationships().toArray(new Relationship[comparer.getSpdxDoc(i).getRelationships().size()]);
146 | Arrays.sort(docRelationships, relationshipComparator);
147 | relationships[i] = docRelationships;
148 | relationshipsIndexes[i] = 0;
149 | }
150 | while (!allRelationshipsExhausted(relationships, relationshipsIndexes)) {
151 | Row currentRow = this.addRow();
152 | Relationship nextRelationship = getNexRelationship(relationships, relationshipsIndexes);
153 | Cell typeCell = currentRow.createCell(TYPE_COL);
154 | typeCell.setCellValue(nextRelationship.getRelationshipType().toString());
155 | for (int i = 0; i < relationships.length; i++) {
156 | if (relationships[i].length > relationshipsIndexes[i]) {
157 | Relationship compareRelationship = relationships[i][relationshipsIndexes[i]];
158 | if (relationshipComparator.compare(nextRelationship, compareRelationship) == 0) {
159 | Cell relationshipCell = currentRow.createCell(FIRST_RELATIONSHIP_COL+i);
160 | relationshipCell.setCellValue(CompareHelper.relationshipToString(relationships[i][relationshipsIndexes[i]]));
161 | relationshipsIndexes[i]++;
162 | }
163 | }
164 | }
165 | }
166 | }
167 |
168 |
169 | /**
170 | * @param relationships
171 | * @param relationshipsIndexes
172 | * @return
173 | */
174 | private Relationship getNexRelationship(Relationship[][] relationships,
175 | int[] relationshipsIndexes) {
176 | Relationship retval = null;
177 | for (int i = 0; i < relationships.length; i++) {
178 | if (relationships[i].length > relationshipsIndexes[i]) {
179 | Relationship candidate = relationships[i][relationshipsIndexes[i]];
180 | if (retval == null || this.relationshipComparator.compare(retval, candidate) > 0) {
181 | retval = candidate;
182 | }
183 | }
184 | }
185 | return retval;
186 | }
187 |
188 | /**
189 | * @param relationships
190 | * @param relationshipsIndexes
191 | * @return
192 | */
193 | private boolean allRelationshipsExhausted(Relationship[][] relationships,
194 | int[] relationshipsIndexes) {
195 | for (int i = 0; i < relationships.length; i++) {
196 | if (relationshipsIndexes[i] < relationships[i].length) {
197 | return false;
198 | }
199 | }
200 | return true;
201 | }
202 |
203 | /* (non-Javadoc)
204 | * @see org.spdx.spdxspreadsheet.AbstractSheet#verify()
205 | */
206 | @Override
207 | public String verify() {
208 | return null; // Nothing to verify
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/examples/org/spdx/examples/SimpleSpdxDocumentV2Compat.java:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: Copyright (c) 2021 Source Auditor Inc.
3 | * SPDX-FileType: SOURCE
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 | package org.spdx.examples;
7 |
8 | import java.io.File;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.io.OutputStream;
12 | import java.text.SimpleDateFormat;
13 | import java.util.Arrays;
14 | import java.util.Date;
15 | import java.util.List;
16 |
17 | import org.spdx.jacksonstore.MultiFormatStore;
18 | import org.spdx.jacksonstore.MultiFormatStore.Format;
19 | import org.spdx.core.InvalidSPDXAnalysisException;
20 | import org.spdx.library.LicenseInfoFactory;
21 | import org.spdx.library.ModelCopyManager;
22 | import org.spdx.library.model.v2.Relationship;
23 | import org.spdx.library.model.v2.SpdxConstantsCompatV2;
24 | import org.spdx.library.model.v2.SpdxDocument;
25 | import org.spdx.library.model.v2.SpdxPackage;
26 | import org.spdx.library.model.v2.enumerations.RelationshipType;
27 | import org.spdx.library.model.v2.license.AnyLicenseInfo;
28 | import org.spdx.storage.IModelStore.IdType;
29 | import org.spdx.storage.ISerializableModelStore;
30 | import org.spdx.storage.simple.InMemSpdxStore;
31 |
32 | /**
33 | * This example demonstrate programmatically creating an SPDX spec version 2.X document, adding document, files
34 | * and saving the document in a JSON file format
35 | *
36 | * This example depends on the Spdx-Java-Library and the spdx-java-jackson store libraries
37 | *
38 | * @author Gary O'Neall
39 | */
40 | public class SimpleSpdxDocumentV2Compat {
41 |
42 | /**
43 | * @param args args[0] is the file path to store the resultant JSON file
44 | */
45 | public static void main(String[] args) {
46 | if (args.length != 1) {
47 | usage();
48 | System.exit(1);
49 | }
50 | File outFile = new File(args[0]);
51 | if (outFile.exists()) {
52 | System.out.println("Output file already exists: "+args[0]);
53 | System.exit(1);
54 | }
55 |
56 | /*
57 | * First thing we need is a store to store document as build the SPDX document
58 | * We'll chose the MultiFormatStore since it supports serializing to JSON files
59 | * It takes an underlying model store as the first parameter - the inMemSpdxStore is a simple
60 | * built in store included in the Spdx-Java-Library. The second parameter is the format
61 | * to use when serializing or deserializing
62 | */
63 | ISerializableModelStore modelStore = new MultiFormatStore(new InMemSpdxStore(), Format.JSON_PRETTY);
64 | /*
65 | * There are several other choices which can be made for a model store - most of which
66 | * are in separate libraries that need to be included as dependencies. Below are a few examples:
67 | * IModelStore modelStore = new InMemSpdxStore(); - the simplest store, but does not support serializing or deserializing
68 | * ISerializableModelStore modelStore = new TagValueStore(new InMemSpdxStore()); Supports serializing and deserializing SPDX tag/value files
69 | * ISerializableModelStore modelStore = new RdfStore(); Supports serializing and deserializing various RDF formats (e.g. RDF/XML, RDF/Turtle)
70 | * ISerializableModelStore modelStore = new SpreadsheetStore(new InMemSpdxStore()); Supports serializing and deserializing .XLS or .XLSX spreadsheets
71 | */
72 |
73 | /*
74 | * The documentUri is a unique identifier for the SPDX documents
75 | */
76 | String documentUri = "https://org.spdx.examples/spdx/doc/b7490f5a-b6ac-45e7-9971-4c27f1db97f7";
77 | /*
78 | * The ModelCopyManager is used when using more than one Model Store. The Listed Licenses uses
79 | * it's own model store, so we will need a ModelCopyManager to manage the copying of the listed
80 | * license information over to the document model store
81 | */
82 | ModelCopyManager copyManager = new ModelCopyManager();
83 | try {
84 | // Time to create the document
85 | SpdxDocument document = new SpdxDocument(modelStore, documentUri, copyManager, false);
86 | // Let's add a few required fields to the document
87 | SimpleDateFormat dateFormat = new SimpleDateFormat(SpdxConstantsCompatV2.SPDX_DATE_FORMAT);
88 | String creationDate = dateFormat.format(new Date());
89 | document.setCreationInfo(document.createCreationInfo(
90 | Arrays.asList(new String[] {"Tool: Simple SPDX Document Example"}),
91 | creationDate));
92 | /*
93 | * Now that we have the initial model object 'document' created, we can use the helper
94 | * methods from that cleass to create any other model elements such as the CreationInfo
95 | * above. These helper functions will use the same Document URI, Model Store and Model Copy Manager
96 | * as the document element.
97 | */
98 | AnyLicenseInfo dataLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2("CC0-1.0");
99 | /*
100 | * Note that by passing in the modelStore and documentUri, the parsed license information is stored
101 | * in the same model store we are using for the document
102 | */
103 | document.setDataLicense(dataLicense);
104 | document.setName("SPDX Example Document");
105 | document.setSpecVersion("SPDX-2.2");
106 |
107 | // Now that we have the basic document information filled in, let's create a package
108 | AnyLicenseInfo pkgConcludedLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2("Apache-2.0 AND MIT");
109 | AnyLicenseInfo pkgDeclaredLicense = LicenseInfoFactory.parseSPDXLicenseStringCompatV2("Apache-2.0");
110 | String pkgId = modelStore.getNextId(IdType.SpdxId);
111 | // The ID's used for SPDX elements must be unique. Calling the model store getNextId function is a
112 | // convenient and safe method to make sure you have a correctly formatted and unique ID
113 | SpdxPackage pkg = document.createPackage(pkgId, "Example Package Name", pkgConcludedLicense,
114 | "Copyright example.org", pkgDeclaredLicense)
115 | .setFilesAnalyzed(false) // Default is true and we don't want to add all the required fields
116 | .setComment("This package is used as an example in creating an SPDX document from scratch")
117 | .setDownloadLocation("NOASSERTION")
118 | .build();
119 | /*
120 | * Note that many of the more complex elements use a builder pattern as in the
121 | * example above
122 | */
123 |
124 | /* Let's add the package relationships to the document
125 | * This step
126 | */
127 | // This step will add a relationship between document and pkg as "DESCRIBES".
128 | document.getDocumentDescribes().add(pkg);
129 | // Let's create another package
130 | pkgId = modelStore.getNextId(IdType.SpdxId);
131 | SpdxPackage childPkg = document.createPackage(pkgId, "Child Example Package Name", pkgConcludedLicense,
132 | "Copyright example.org", pkgDeclaredLicense)
133 | .setFilesAnalyzed(false) // Default is true and we don't want to add all the required fields
134 | .setComment("This package is used as an example in creating an SPDX document from scratch")
135 | .setDownloadLocation("NOASSERTION")
136 | .build();
137 | // Then create a DEPEND_ON relation by relationship factory
138 | Relationship relationship = pkg.createRelationship(childPkg, RelationshipType.DEPENDS_ON, "");
139 | pkg.addRelationship(relationship);
140 |
141 | // That's for creating the simple document. Let's verify to make sure nothing is out of spec
142 | List warnings = document.verify();
143 | if (warnings.size() > 0) {
144 | System.out.println("The document has the following warnings:");
145 | for (String warning:warnings) {
146 | System.out.print("\t");
147 | System.out.println(warning);
148 | }
149 | }
150 | // Last step is to serialize
151 | try (OutputStream outputStream = new FileOutputStream(outFile)) {
152 | modelStore.serialize(outputStream);
153 | }
154 | System.out.println("Example document written to "+args[0]);
155 | System.exit(0);
156 | } catch (InvalidSPDXAnalysisException e) {
157 | System.out.println("Unexpected error creating SPDX document: "+e.getMessage());
158 | System.exit(1);
159 | } catch (IOException e) {
160 | System.out.println("I/O error writing output JSON file");
161 | System.exit(1);
162 | }
163 |
164 |
165 | }
166 |
167 | private static void usage() {
168 | System.out.println("Usage: SimpleSpxDocument outputFilePath");
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------