diff --git a/backend/src-common/pom.xml b/backend/src-common/pom.xml index fe223ceaf3..c2a23ca490 100644 --- a/backend/src-common/pom.xml +++ b/backend/src-common/pom.xml @@ -37,11 +37,24 @@ + + + com.googlecode.json-simple + json-simple + 1.1.1 + compile + org.spdx spdx-tools compile + + org.spdx + tools-java + 1.0.2 + compile + org.apache.logging.log4j diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/DocumentCreationInformationSummary.java b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/DocumentCreationInformationSummary.java new file mode 100644 index 0000000000..237dd7f02f --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/DocumentCreationInformationSummary.java @@ -0,0 +1,38 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +public class DocumentCreationInformationSummary extends DocumentSummary { + + @Override + protected DocumentCreationInformation summary(SummaryType type, DocumentCreationInformation document) { + // Copy required details + DocumentCreationInformation copy = new DocumentCreationInformation(); + + switch (type) { + case SUMMARY: + copyField(document, copy, DocumentCreationInformation._Fields.ID); + copyField(document, copy, DocumentCreationInformation._Fields.SPDXID); + copyField(document, copy, DocumentCreationInformation._Fields.NAME); + break; + default: + break; + } + + return copy; + } + + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/FileInformationSummary.java b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/FileInformationSummary.java new file mode 100644 index 0000000000..85b729eacf --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/FileInformationSummary.java @@ -0,0 +1,38 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.fileinformation.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +public class FileInformationSummary extends DocumentSummary { + + @Override + protected FileInformation summary(SummaryType type, FileInformation document) { + // Copy required details + FileInformation copy = new FileInformation(); + + switch (type) { + case SUMMARY: + copyField(document, copy, FileInformation._Fields.ID); + copyField(document, copy, FileInformation._Fields.SPDXID); + copyField(document, copy, FileInformation._Fields.FILE_NAME); + break; + default: + break; + } + + return copy; + } + + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/PackageInformationSummary.java b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/PackageInformationSummary.java new file mode 100644 index 0000000000..2b343a90c6 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/PackageInformationSummary.java @@ -0,0 +1,37 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +public class PackageInformationSummary extends DocumentSummary { + + @Override + protected PackageInformation summary(SummaryType type, PackageInformation document) { + // Copy required details + PackageInformation copy = new PackageInformation(); + + switch (type) { + case SUMMARY: + copyField(document, copy, PackageInformation._Fields.ID); + copyField(document, copy, PackageInformation._Fields.SPDXID); + copyField(document, copy, PackageInformation._Fields.NAME); + break; + default: + break; + } + + return copy; + } + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/SpdxDocumentSummary.java b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/SpdxDocumentSummary.java new file mode 100644 index 0000000000..d771b2dfe3 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/SpdxDocumentSummary.java @@ -0,0 +1,38 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +public class SpdxDocumentSummary extends DocumentSummary { + + @Override + protected SPDXDocument summary(SummaryType type, SPDXDocument document) { + // Copy required details + SPDXDocument copy = new SPDXDocument(); + + switch (type) { + case SUMMARY: + copyField(document, copy, SPDXDocument._Fields.ID); + copyField(document, copy, SPDXDocument._Fields.SPDX_DOCUMENT_CREATION_INFO_ID); + copyField(document, copy, SPDXDocument._Fields.SPDX_PACKAGE_INFO_IDS); + copyField(document, copy, SPDXDocument._Fields.SPDX_FILE_INFO_IDS); + default: + break; + } + + return copy; + } + + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ChangeLogsDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ChangeLogsDatabaseHandler.java index 13eb4b284c..757469216d 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ChangeLogsDatabaseHandler.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ChangeLogsDatabaseHandler.java @@ -59,7 +59,6 @@ public List getChangeLogsByDocumentId(User user, String docId) { changeLogsByDocId = changeLogsByDocId.stream().filter(Objects::nonNull).filter(changeLog -> isNotEmptyChangeLog(changeLog)) .collect(Collectors.toList()); Collections.sort(changeLogsByDocId, Comparator.comparing(ChangeLogs::getChangeTimestamp).reversed()); - changeLogsByDocId.stream().forEach(cl -> cl.setChangeTimestamp(cl.getChangeTimestamp().split(" ")[0])); return changeLogsByDocId; } diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java index e71ef9797b..798fbec45f 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java @@ -25,6 +25,7 @@ import org.eclipse.sw360.datahandler.common.ThriftEnumUtils; import org.eclipse.sw360.datahandler.couchdb.AttachmentConnector; import org.eclipse.sw360.datahandler.couchdb.AttachmentStreamConnector; +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentDatabaseHandler; import org.eclipse.sw360.datahandler.entitlement.ComponentModerator; import org.eclipse.sw360.datahandler.entitlement.ProjectModerator; import org.eclipse.sw360.datahandler.entitlement.ReleaseModerator; @@ -60,12 +61,25 @@ import org.apache.thrift.TException; import org.eclipse.sw360.spdx.SpdxBOMImporter; import org.eclipse.sw360.spdx.SpdxBOMImporterSink; +import org.eclipse.sw360.spdx.SpdxBOMExporter; +import org.eclipse.sw360.spdx.SpdxBOMExporterSink; import org.jetbrains.annotations.NotNull; import org.spdx.rdfparser.InvalidSPDXAnalysisException; - +import org.spdx.tools.SpdxConverter; +import org.spdx.tools.SpdxConverterException; +import org.spdx.tools.TagToRDF; + +import java.io.BufferedReader; +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 java.io.InputStreamReader; import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -111,6 +125,7 @@ public class ComponentDatabaseHandler extends AttachmentAwareDatabaseHandler { private DatabaseHandlerUtil dbHandlerUtil; private final AttachmentConnector attachmentConnector; + private final SpdxDocumentDatabaseHandler spdxDocumentDatabaseHandler; /** * Access to moderation */ @@ -160,6 +175,9 @@ public ComponentDatabaseHandler(Supplier httpClient, String dbNa attachmentConnector = new AttachmentConnector(httpClient, attachmentDbName, durationOf(30, TimeUnit.SECONDS)); DatabaseConnectorCloudant dbChangeLogs = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_CHANGE_LOGS); this.dbHandlerUtil = new DatabaseHandlerUtil(dbChangeLogs); + + // Create the spdx document database handler + this.spdxDocumentDatabaseHandler = new SpdxDocumentDatabaseHandler(httpClient, DatabaseSettings.COUCH_DB_SPDX); } public ComponentDatabaseHandler(Supplier httpClient, String dbName, String changeLogsDbName, String attachmentDbName, ComponentModerator moderator, ReleaseModerator releaseModerator, ProjectModerator projectModerator) throws MalformedURLException { @@ -513,12 +531,26 @@ public AddDocumentRequestSummary addRelease(Release release, User user) throws S } private boolean isDuplicate(Component component, boolean caseInsenstive){ - Set duplicates = componentRepository.getComponentIdsByName(component.getName(), caseInsenstive); - return duplicates.size()>0; + return isDuplicate(component.getName(), caseInsenstive); } private boolean isDuplicate(Release release){ - List duplicates = releaseRepository.searchByNameAndVersion(release.getName(), release.getVersion()); + return isDuplicate(release.getName(), release.getVersion()); + } + + private boolean isDuplicate(String componentName, boolean caseInsenstive) { + if (isNullEmptyOrWhitespace(componentName)) { + return false; + } + Set duplicates = componentRepository.getComponentIdsByName(componentName, caseInsenstive); + return duplicates.size()>0; + } + + private boolean isDuplicate(String releaseName, String releaseVersion) { + if (isNullEmptyOrWhitespace(releaseName)) { + return false; + } + List duplicates = releaseRepository.searchByNameAndVersion(releaseName, releaseVersion); return duplicates.size()>0; } @@ -1679,6 +1711,12 @@ public RequestStatus deleteRelease(String id, User user) throws SW360Exception { Component componentBefore = componentRepository.get(release.getComponentId()); // Remove release id from component removeReleaseId(id, release.componentId); + // Remove spdx if exist + String spdxId = release.getSpdxId(); + if (CommonUtils.isNotNullEmptyOrWhitespace(spdxId)) { + spdxDocumentDatabaseHandler.deleteSPDXDocument(spdxId, user); + release = releaseRepository.get(id); + } Component componentAfter=removeReleaseAndCleanUp(release, user); dbHandlerUtil.addChangeLogs(null, release, user.getEmail(), Operation.DELETE, attachmentConnector, Lists.newArrayList(), null, null); @@ -2363,21 +2401,208 @@ private void sendMailNotificationsForReleaseUpdate(Release release, String user) release.getName(), release.getVersion()); } - public RequestSummary importBomFromAttachmentContent(User user, String attachmentContentId) throws SW360Exception { + public ImportBomRequestPreparation prepareImportBom(User user, String attachmentContentId) throws SW360Exception { final AttachmentContent attachmentContent = attachmentConnector.getAttachmentContent(attachmentContentId); final Duration timeout = Duration.durationOf(30, TimeUnit.SECONDS); + String sourceFilePath = null; + String targetFilePath = null; try { final AttachmentStreamConnector attachmentStreamConnector = new AttachmentStreamConnector(timeout); try (final InputStream inputStream = attachmentStreamConnector.unsafeGetAttachmentStream(attachmentContent)) { final SpdxBOMImporterSink spdxBOMImporterSink = new SpdxBOMImporterSink(user, null, this); final SpdxBOMImporter spdxBOMImporter = new SpdxBOMImporter(spdxBOMImporterSink); - return spdxBOMImporter.importSpdxBOMAsRelease(inputStream, attachmentContent); + + InputStream spdxInputStream = null; + String fileType = getFileType(attachmentContent.getFilename()); + + if (!fileType.equals("rdf")) { + final String ext = "." + fileType; + final File sourceFile = DatabaseHandlerUtil.saveAsTempFile(user, inputStream, attachmentContentId, ext); + sourceFilePath = sourceFile.getAbsolutePath(); + targetFilePath = sourceFilePath.replace(ext, ".rdf"); + File targetFile = null; + try { + if (fileType.equals("spdx")) { + targetFile = convertTagToRdf(sourceFile, targetFilePath); + } else { + SpdxConverter.convert(sourceFilePath, targetFilePath); + targetFile = new File(targetFilePath); + } + spdxInputStream = new FileInputStream(targetFile); + } catch (SpdxConverterException e) { + log.error("Can not convert to RDF \n" + e); + ImportBomRequestPreparation importBomRequestPreparation = new ImportBomRequestPreparation(); + importBomRequestPreparation.setRequestStatus(RequestStatus.FAILURE); + importBomRequestPreparation.setMessage("error-convert"); + return importBomRequestPreparation; + + } finally { + Files.delete(Paths.get(sourceFilePath)); + } + } else { + final String ext = "." + fileType; + final File sourceFile = DatabaseHandlerUtil.saveAsTempFile(user, inputStream, attachmentContentId, ext); + sourceFilePath = sourceFile.getAbsolutePath(); + cutFileInformation(sourceFilePath); + File targetFile = new File (sourceFilePath); + spdxInputStream = new FileInputStream(targetFile); + targetFilePath = sourceFilePath; + } + + ImportBomRequestPreparation importBomRequestPreparation = spdxBOMImporter.prepareImportSpdxBOMAsRelease(spdxInputStream, attachmentContent); + if (RequestStatus.SUCCESS.equals(importBomRequestPreparation.getRequestStatus())) { + String name = importBomRequestPreparation.getName(); + String version = importBomRequestPreparation.getVersion(); + if (!isDuplicate(name, true)) { + importBomRequestPreparation.setIsComponentDuplicate(false); + importBomRequestPreparation.setIsReleaseDuplicate(false); + } else if (!isDuplicate(name, version)) { + importBomRequestPreparation.setIsComponentDuplicate(true); + importBomRequestPreparation.setIsReleaseDuplicate(false); + } else { + importBomRequestPreparation.setIsComponentDuplicate(true); + importBomRequestPreparation.setIsReleaseDuplicate(true); + } + importBomRequestPreparation.setMessage(targetFilePath); + } + + return importBomRequestPreparation; } } catch (InvalidSPDXAnalysisException | IOException e) { throw new SW360Exception(e.getMessage()); } } + private void cutFileInformation(String pathFile) { + try { + log.info("Run command cut File information from RDF file from line"); + String command = "file=\"" + pathFile + "\" " + + "&& start=$(cat $file | grep -nF \"spdx:hasFile>\" | head -1 | cut -d \":\" -f1) " + + "&& end=$(cat $file | grep -nF \"/spdx:hasFile>\" | tail -1 | cut -d \":\" -f1) " + + "&& echo $start to $end " + + "&& sed -i \"${start},${end}d\" $file "; + Process process = Runtime.getRuntime().exec(new String[] { "/bin/bash", "-c", command }); + printResults(process); + } catch (IOException e) { + log.error("Error when cut File information"); + e.printStackTrace(); + } + } + + public static void printResults(Process process) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line = ""; + while ((line = reader.readLine()) != null) { + log.info(line); + } + } + + private File convertTagToRdf(File sourceFile, String targetFilePath) { + FileInputStream spdxTagStream = null; + + try { + spdxTagStream = new FileInputStream(sourceFile); + } catch (FileNotFoundException e2) { + e2.printStackTrace(); + } + + File spdxRDFFile = new File(targetFilePath); + String outputFormat = "RDF/XML"; + FileOutputStream outStream = null; + try { + outStream = new FileOutputStream(spdxRDFFile); + } catch (FileNotFoundException e1) { + try { + spdxTagStream.close(); + } catch (IOException e) { + log.error("Warning: Unable to close input file on error."); + } + log.error("Could not write to the new SPDX RDF file " + spdxRDFFile.getPath() + "due to error " + e1.getMessage()); + } + + List warnings = new ArrayList(); + try { + TagToRDF.convertTagFileToRdf(spdxTagStream, outStream, outputFormat, warnings); + if (!warnings.isEmpty()) { + log.warn("The following warnings and or verification errors were found:"); + for (String warning:warnings) { + log.warn("\t" + warning); + } + } + } catch (Exception e) { + log.error("Error creating SPDX Analysis: " + e.getMessage()); + } finally { + if (outStream != null) { + try { + outStream.close(); + } catch (IOException e) { + log.error("Error closing RDF file: " + e.getMessage()); + } + } + if (spdxTagStream != null) { + try { + spdxTagStream.close(); + } catch (IOException e) { + log.error("Error closing Tag/Value file: " + e.getMessage()); + } + } + } + return spdxRDFFile; + } + + public RequestSummary exportSPDX(User user, String releaseId, String outputFormat) throws SW360Exception { + RequestSummary requestSummary = new RequestSummary(); + + try { + final SpdxBOMExporterSink spdxBOMExporterSink = new SpdxBOMExporterSink(user, null, this); + final SpdxBOMExporter spdxBOMExporter = new SpdxBOMExporter(spdxBOMExporterSink); + try { + return spdxBOMExporter.exportSPDXFile(releaseId, outputFormat); + } catch (InvalidSPDXAnalysisException e) { + e.printStackTrace(); + } + } catch (IOException e) { + throw new SW360Exception(e.getMessage()); + } + return requestSummary.setRequestStatus(RequestStatus.FAILURE); + } + + public RequestSummary importBomFromAttachmentContent(User user, String attachmentContentId, String newReleaseVersion, String releaseId, String rdfFilePath) throws SW360Exception { + final AttachmentContent attachmentContent = attachmentConnector.getAttachmentContent(attachmentContentId); + try { + final SpdxBOMImporterSink spdxBOMImporterSink = new SpdxBOMImporterSink(user, null, this); + final SpdxBOMImporter spdxBOMImporter = new SpdxBOMImporter(spdxBOMImporterSink); + InputStream spdxInputStream = null; + if (!isNullEmptyOrWhitespace(rdfFilePath)) { + spdxInputStream = new FileInputStream(new File(rdfFilePath)); + Files.delete(Paths.get(rdfFilePath)); + } else { + spdxInputStream = attachmentConnector.unsafeGetAttachmentStream(attachmentContent); + } + return spdxBOMImporter.importSpdxBOMAsRelease(spdxInputStream, attachmentContent, newReleaseVersion, releaseId); + } catch (IOException e) { + throw new SW360Exception(e.getMessage()); + } + } + + private String getFileType(String fileName) { + if (isNullEmptyOrWhitespace(fileName) || !fileName.contains(".")) { + log.error("Can not get file type from file name - no file extension"); + return null; + } + String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + if ("xml".equals(ext)) { + if (fileName.endsWith("rdf.xml")) { + ext = "rdf"; + } + } + return ext; + } + + private boolean isJSONFile(String fileType) { + return (!isNullEmptyOrWhitespace(fileType) && fileType.equals("json")); + } + private void removeLeadingTrailingWhitespace(Release release) { DatabaseHandlerUtil.trimStringFields(release, listOfStringFieldsInReleaseToTrim); diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/DatabaseHandlerUtil.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/DatabaseHandlerUtil.java index 37a24af415..b175908500 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/DatabaseHandlerUtil.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/DatabaseHandlerUtil.java @@ -10,6 +10,7 @@ package org.eclipse.sw360.datahandler.db; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -44,6 +45,7 @@ import java.util.stream.Collectors; import org.apache.logging.log4j.Level; +import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; @@ -75,6 +77,7 @@ import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.RepositoryMixin; import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.VendorMixin; import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.ObligationMixin; +import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.*; import org.eclipse.sw360.datahandler.thrift.ProjectReleaseRelationship; import org.eclipse.sw360.datahandler.thrift.RequestStatus; import org.eclipse.sw360.datahandler.thrift.SW360Exception; @@ -99,6 +102,19 @@ import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; import org.eclipse.sw360.datahandler.thrift.users.User; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.CheckSum; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.Creator; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.ExternalDocumentReferences; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetRange; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; import org.eclipse.sw360.datahandler.thrift.licenses.Obligation; import com.fasterxml.jackson.core.JsonProcessingException; @@ -124,6 +140,7 @@ public class DatabaseHandlerUtil { private static final boolean IS_STORE_ATTACHMENT_TO_FILE_SYSTEM_ENABLED; private static final String ATTACHMENT_STORE_FILE_SYSTEM_LOCATION; private static final String ATTACHMENT_STORE_FILE_SYSTEM_PERMISSION; + // private static final String TEMPLE_FILE_LOCATION; private static ExecutorService ATTACHMENT_FILE_SYSTEM_STORE_THREAD_POOL = Executors.newFixedThreadPool(5); private static final String ATTACHMENT_DELETE_NO_OF_DAYS; private static final boolean IS_SW360CHANGELOG_ENABLED; @@ -139,6 +156,7 @@ public class DatabaseHandlerUtil { "/opt/sw360tempattachments"); ATTACHMENT_STORE_FILE_SYSTEM_PERMISSION = props.getProperty("attachment.store.file.system.permission", "rwx------"); + // TEMPLE_FILE_LOCATION = props.getProperty("temp.dir", "../temp") IS_STORE_ATTACHMENT_TO_FILE_SYSTEM_ENABLED = Boolean.parseBoolean(props.getProperty("enable.attachment.store.to.file.system", "false")); ATTACHMENT_DELETE_NO_OF_DAYS = props.getProperty("attachemnt.delete.no.of.days", "30"); @@ -404,6 +422,21 @@ public static void trimStringFields(T obj, List listOfStrFields) { changeLog.setDocumentId(newProjVer.getId()); changeLog.setDocumentType(newProjVer.getType()); changeLog.setDbName(DatabaseSettings.COUCH_DB_DATABASE); + } else if (newDocVersion instanceof SPDXDocument) { + SPDXDocument newProjVer = (SPDXDocument) newDocVersion; + changeLog.setDocumentId(newProjVer.getId()); + changeLog.setDocumentType(newProjVer.getType()); + changeLog.setDbName(DatabaseSettings.COUCH_DB_SPDX); + } else if (newDocVersion instanceof DocumentCreationInformation) { + DocumentCreationInformation newProjVer = (DocumentCreationInformation) newDocVersion; + changeLog.setDocumentId(newProjVer.getId()); + changeLog.setDocumentType(newProjVer.getType()); + changeLog.setDbName(DatabaseSettings.COUCH_DB_SPDX); + } else if (newDocVersion instanceof PackageInformation) { + PackageInformation newProjVer = (PackageInformation) newDocVersion; + changeLog.setDocumentId(newProjVer.getId()); + changeLog.setDocumentType(newProjVer.getType()); + changeLog.setDbName(DatabaseSettings.COUCH_DB_SPDX); } else if (newDocVersion instanceof Obligation) { Obligation newProjVer = (Obligation) newDocVersion; changeLog.setDocumentId(newProjVer.getId()); @@ -411,8 +444,6 @@ public static void trimStringFields(T obj, List listOfStrFields) { changeLog.setDbName(DatabaseSettings.COUCH_DB_DATABASE); } - log.info("Initialize ChangeLogs for Document Id : " + changeLog.getDocumentId()); - if (parentOperation != null) info.put("PARENT_OPERATION", parentOperation.name()); if (!info.isEmpty()) @@ -581,6 +612,12 @@ private static void changeLogsForNewlyCreatedOrDeleted(T newor fields = Release._Fields.values(); } else if (neworDeletedVersion instanceof ModerationRequest) { fields = ModerationRequest._Fields.values(); + } else if (neworDeletedVersion instanceof SPDXDocument) { + fields = SPDXDocument._Fields.values(); + } else if (neworDeletedVersion instanceof DocumentCreationInformation) { + fields = DocumentCreationInformation._Fields.values(); + } else if (neworDeletedVersion instanceof PackageInformation) { + fields = PackageInformation._Fields.values(); } else if (neworDeletedVersion instanceof Obligation) { fields = Obligation._Fields.values(); } else { @@ -607,6 +644,12 @@ private static void changeLogsForNewlyCreatedOrDeleted(T newor fields = Release._Fields.values(); } else if (newVersion instanceof ModerationRequest) { fields = ModerationRequest._Fields.values(); + } else if (newVersion instanceof SPDXDocument) { + fields = SPDXDocument._Fields.values(); + } else if (newVersion instanceof DocumentCreationInformation) { + fields = DocumentCreationInformation._Fields.values(); + } else if (newVersion instanceof PackageInformation) { + fields = PackageInformation._Fields.values(); } else if (newVersion instanceof Obligation) { fields = Obligation._Fields.values(); } else { @@ -690,7 +733,7 @@ private static boolean isTwoCollectionSame(Collection col1, Collection col } private static String getTimeStamp() { - SimpleDateFormat timestampPattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + SimpleDateFormat timestampPattern = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS"); Date timeNow = new Date(System.currentTimeMillis()); return timestampPattern.format(timeNow); } @@ -823,6 +866,16 @@ private static ObjectMapper initAndGetObjectMapper() { mapper.addMixInAnnotations(Repository.class, RepositoryMixin.class); mapper.addMixInAnnotations(ProjectProjectRelationship.class, ProjectProjectRelationshipMixin.class); mapper.addMixInAnnotations(ProjectReleaseRelationship.class, ProjectReleaseRelationshipMixin.class); + mapper.addMixInAnnotations(CheckSum.class, CheckSumMixin.class); + mapper.addMixInAnnotations(Annotations.class, AnnotationsMixin.class); + mapper.addMixInAnnotations(ExternalDocumentReferences.class, ExternalDocumentReferencesMixin.class); + mapper.addMixInAnnotations(Creator.class, CreatorMixin.class); + mapper.addMixInAnnotations(OtherLicensingInformationDetected.class, OtherLicensingInformationDetectedMixin.class); + mapper.addMixInAnnotations(PackageVerificationCode.class, PackageVerificationCodeMixin.class); + mapper.addMixInAnnotations(ExternalReference.class, ExternalReferenceMixin.class); + mapper.addMixInAnnotations(RelationshipsBetweenSPDXElements.class, RelationshipsBetweenSPDXElementsMixin.class); + mapper.addMixInAnnotations(SnippetInformation.class, SnippetInformationMixin.class); + mapper.addMixInAnnotations(SnippetRange.class, SnippetRangeMixin.class); mapper.addMixInAnnotations(Obligation.class, ObligationMixin.class); } return mapper; @@ -979,5 +1032,14 @@ private static void configureLog4J(String outputpath, String liferayhome) { .add( builder.newAppenderRef("ChangeLogFile"))); Configurator.reconfigure(builder.build()); } + public static File saveAsTempFile(User user, InputStream inputStream, String prefix, String suffix) throws IOException { + final File tempFile = File.createTempFile(prefix, suffix); + tempFile.deleteOnExit(); + // Set append to false, overwrite if file existed + try (FileOutputStream outputStream = new FileOutputStream(tempFile, false)) { + IOUtils.copy(inputStream, outputStream); + } + return tempFile; + } } diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentDatabaseHandler.java new file mode 100644 index 0000000000..bc3c7a5356 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentDatabaseHandler.java @@ -0,0 +1,224 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.document; + +import com.cloudant.client.api.CloudantClient; + +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import org.eclipse.sw360.datahandler.thrift.*; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.components.*; +import org.eclipse.sw360.datahandler.thrift.changelogs.*; +import org.eclipse.sw360.datahandler.db.ReleaseRepository; +import org.eclipse.sw360.datahandler.db.VendorRepository; +import org.eclipse.sw360.datahandler.db.DatabaseHandlerUtil; +import org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo.SpdxDocumentCreationInfoDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.packageinfo.SpdxPackageInfoDatabaseHandler; +import org.eclipse.sw360.datahandler.entitlement.SpdxDocumentModerator; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; +import org.eclipse.sw360.datahandler.common.CommonUtils; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +import java.net.MalformedURLException; +import java.util.*; +import java.util.function.Supplier; +import com.google.common.collect.Lists; + +import static org.eclipse.sw360.datahandler.common.SW360Assert.assertNotNull; +import static org.eclipse.sw360.datahandler.common.CommonUtils.*; +import static org.eclipse.sw360.datahandler.permissions.PermissionUtils.makePermission; +import static org.eclipse.sw360.datahandler.thrift.ThriftValidate.prepareSPDXDocument; + +public class SpdxDocumentDatabaseHandler { + + private static final Logger log = LogManager.getLogger(SpdxDocumentDatabaseHandler.class); + + /** + * Connection to the couchDB database + */ + private final DatabaseConnectorCloudant db; + private final DatabaseConnectorCloudant sw360db; + private final DatabaseConnectorCloudant dbChangeLogs; + + private final SpdxDocumentRepository SPDXDocumentRepository; + private final ReleaseRepository releaseRepository; + private final VendorRepository vendorRepository; + private DatabaseHandlerUtil dbHandlerUtil; + private final SpdxDocumentModerator moderator; + + private final SpdxDocumentCreationInfoDatabaseHandler creationInfoDatabaseHandler; + private final SpdxPackageInfoDatabaseHandler packageInfoDatabaseHandler; + + public SpdxDocumentDatabaseHandler(Supplier httpClient, String dbName) throws MalformedURLException { + db = new DatabaseConnectorCloudant(httpClient, dbName); + + // Create the repositories + SPDXDocumentRepository = new SpdxDocumentRepository(db); + + sw360db = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_DATABASE); + vendorRepository = new VendorRepository(sw360db); + releaseRepository = new ReleaseRepository(sw360db, vendorRepository); + // Create the moderator + moderator = new SpdxDocumentModerator(); + // Create the changelogs + dbChangeLogs = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_CHANGE_LOGS); + this.dbHandlerUtil = new DatabaseHandlerUtil(dbChangeLogs); + this.creationInfoDatabaseHandler = new SpdxDocumentCreationInfoDatabaseHandler(httpClient, dbName); + this.packageInfoDatabaseHandler = new SpdxPackageInfoDatabaseHandler(httpClient, dbName); + } + + public List getSPDXDocumentSummary(User user) { + List spdxs = SPDXDocumentRepository.getSPDXDocumentSummary(); + return spdxs; + } + + public SPDXDocument getSPDXDocumentById(String id, User user) throws SW360Exception { + SPDXDocument spdx = SPDXDocumentRepository.get(id); + assertNotNull(spdx, "Could not find SPDX Document by id: " + id); + // Set permissions + if (user != null) { + makePermission(spdx, user).fillPermissions(); + } + return spdx; + } + + public SPDXDocument getSPDXDocumentForEdit(String id, User user) throws SW360Exception { + List moderationRequestsForDocumentId = moderator.getModerationRequestsForDocumentId(id); + + SPDXDocument spdx = getSPDXDocumentById(id, user); + DocumentState documentState; + + if (moderationRequestsForDocumentId.isEmpty()) { + documentState = CommonUtils.getOriginalDocumentState(); + } else { + final String email = user.getEmail(); + Optional moderationRequestOptional = CommonUtils.getFirstModerationRequestOfUser(moderationRequestsForDocumentId, email); + if (moderationRequestOptional.isPresent() + && isInProgressOrPending(moderationRequestOptional.get())){ + ModerationRequest moderationRequest = moderationRequestOptional.get(); + spdx = moderator.updateSPDXDocumentFromModerationRequest(spdx, moderationRequest.getSPDXDocumentAdditions(), moderationRequest.getSPDXDocumentDeletions()); + documentState = CommonUtils.getModeratedDocumentState(moderationRequest); + } else { + documentState = new DocumentState().setIsOriginalDocument(true).setModerationState(moderationRequestsForDocumentId.get(0).getModerationState()); + } + } + spdx.setPermissions(makePermission(spdx, user).getPermissionMap()); + spdx.setDocumentState(documentState); + return spdx; + } + + public AddDocumentRequestSummary addSPDXDocument(SPDXDocument spdx, User user) throws SW360Exception { + AddDocumentRequestSummary requestSummary= new AddDocumentRequestSummary(); + prepareSPDXDocument(spdx); + String releaseId = spdx.getReleaseId(); + Release release = releaseRepository.get(releaseId); + assertNotNull(release, "Could not find Release to add SPDX Document!"); + if (isNotNullEmptyOrWhitespace(release.getSpdxId())){ + log.error("SPDX Document existed in release!"); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.DUPLICATE) + .setId(release.getSpdxId()); + } + spdx.setCreatedBy(user.getEmail()); + SPDXDocumentRepository.add(spdx); + String spdxId = spdx.getId(); + release.setSpdxId(spdxId); + releaseRepository.update(release); + dbHandlerUtil.addChangeLogs(spdx, null, user.getEmail(), Operation.CREATE, null, Lists.newArrayList(), null, null); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.SUCCESS) + .setId(spdx.getId()); + } + + public RequestStatus updateSPDXDocument(SPDXDocument spdx, User user) throws SW360Exception { + prepareSPDXDocument(spdx); + SPDXDocument actual = SPDXDocumentRepository.get(spdx.getId()); + assertNotNull(actual, "Could not find SPDX Document to update!"); + if (!makePermission(spdx, user).isActionAllowed(RequestedAction.WRITE)) { + if (isChanged(actual, spdx)) { + return moderator.updateSPDXDocument(spdx, user); + } else { + return RequestStatus.SUCCESS; + } + } + SPDXDocumentRepository.update(spdx); + dbHandlerUtil.addChangeLogs(spdx, actual, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), null, null); + return RequestStatus.SUCCESS; + } + + public RequestStatus updateSPDXDocumentFromModerationRequest(SPDXDocument spdxAdditions, SPDXDocument spdxDeletions, User user) throws SW360Exception { + try { + SPDXDocument spdx = getSPDXDocumentById(spdxAdditions.getId(), user); + spdx = moderator.updateSPDXDocumentFromModerationRequest(spdx, spdxAdditions, spdxDeletions); + return updateSPDXDocument(spdx, user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Document when updating from moderation request."); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deleteSPDXDocument(String id, User user) throws SW360Exception { + SPDXDocument spdx = SPDXDocumentRepository.get(id); + assertNotNull(spdx, "Could not find SPDX Document to delete!"); + if (!makePermission(spdx, user).isActionAllowed(RequestedAction.WRITE)) { + return moderator.deleteSPDXDocument(spdx, user); + } + Set packageInfoIds = spdx.getSpdxPackageInfoIds(); + if (packageInfoIds != null) { + for (String packageInfoId : packageInfoIds) { + packageInfoDatabaseHandler.deletePackageInformation(packageInfoId, user); + } + } + + Set fileInfoIds = spdx.getSpdxFileInfoIds(); + if (fileInfoIds != null) { + return RequestStatus.IN_USE; + } + + String documentCreationId = spdx.getSpdxDocumentCreationInfoId(); + if (documentCreationId != null) { + creationInfoDatabaseHandler.deleteDocumentCreationInformation(documentCreationId, user); + } + + spdx.unsetSpdxPackageInfoIds(); + spdx.unsetSpdxDocumentCreationInfoId(); + + SPDXDocumentRepository.remove(id); + String releaseId = spdx.getReleaseId(); + if (isNotNullEmptyOrWhitespace(releaseId)) { + Release release = releaseRepository.get(releaseId); + assertNotNull(release, "Could not remove SPDX Document ID in Release!"); + Release oldRelease = release.deepCopy(); + release.unsetSpdxId(); + releaseRepository.update(release); + dbHandlerUtil.addChangeLogs(release, oldRelease, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), spdx.getId(), Operation.SPDXDOCUMENT_DELETE); + } + return RequestStatus.SUCCESS; + } + + private boolean isChanged(SPDXDocument actual, SPDXDocument update) { + + for (SPDXDocument._Fields field : SPDXDocument._Fields.values()) { + if(update.getFieldValue(field) == null) { + continue; + } else if (actual.getFieldValue(field) == null) { + return true; + } else if (!actual.getFieldValue(field).equals(update.getFieldValue(field))) { + return true; + } + } + + return false; + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentRepository.java new file mode 100644 index 0000000000..f973e2eb9b --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.document; + +import org.eclipse.sw360.components.summary.SpdxDocumentSummary; +import org.eclipse.sw360.components.summary.SummaryType; +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.couchdb.SummaryAwareRepository; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; + +import com.cloudant.client.api.model.DesignDocument.MapReduce; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SpdxDocumentRepository extends SummaryAwareRepository { + + private static final String ALL = "function(doc) { if (doc.type == 'SPDXDocument') emit(null, doc._id) }"; + + public SpdxDocumentRepository(DatabaseConnectorCloudant db) { + super(SPDXDocument.class, db, new SpdxDocumentSummary()); + Map views = new HashMap(); + views.put("all", createMapReduce(ALL, null)); + initStandardDesignDocument(views, db); + } + + public List getSPDXDocumentSummary() { + return makeSummary(SummaryType.SUMMARY, getAllIds()); + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentSearchHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentSearchHandler.java new file mode 100644 index 0000000000..f440bf53a2 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentSearchHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.document; + +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector; +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneSearchView; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.ektorp.http.HttpClient; + +import com.cloudant.client.api.CloudantClient; + +import java.io.IOException; +import java.util.List; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector.prepareWildcardQuery; + +public class SpdxDocumentSearchHandler { + + private static final LuceneSearchView luceneSearchView + = new LuceneSearchView("lucene", "SPDXDocument", + "function(doc) {" + + " if(doc.type == 'SPDXDocument') { " + + " var ret = new Document();" + + " ret.add(doc._id); " + + " return ret;" + + " }" + + "}"); + + private final LuceneAwareDatabaseConnector connector; + + public SpdxDocumentSearchHandler(Supplier httpClient, Supplier cClient, String dbName) throws IOException { + connector = new LuceneAwareDatabaseConnector(httpClient, cClient, dbName); + connector.addView(luceneSearchView); + } + + public List search(String searchText) { + return connector.searchView(SPDXDocument.class, luceneSearchView, prepareWildcardQuery(searchText)); + } +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoDatabaseHandler.java new file mode 100644 index 0000000000..c6d1e9c588 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoDatabaseHandler.java @@ -0,0 +1,191 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo; + +import com.cloudant.client.api.CloudantClient; + +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentRepository; +import org.eclipse.sw360.datahandler.thrift.*; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.changelogs.*; +import org.eclipse.sw360.datahandler.db.DatabaseHandlerUtil; +import org.eclipse.sw360.datahandler.entitlement.SpdxDocumentCreationInfoModerator; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; +import org.eclipse.sw360.datahandler.common.CommonUtils; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +import java.net.MalformedURLException; +import java.util.*; +import java.util.function.Supplier; +import com.google.common.collect.Lists; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import static org.eclipse.sw360.datahandler.common.CommonUtils.*; +import static org.eclipse.sw360.datahandler.common.SW360Assert.assertNotNull; +import static org.eclipse.sw360.datahandler.permissions.PermissionUtils.makePermission; +import static org.eclipse.sw360.datahandler.thrift.ThriftValidate.prepareSpdxDocumentCreationInfo; + +public class SpdxDocumentCreationInfoDatabaseHandler { + + private static final Logger log = LogManager.getLogger(SpdxDocumentCreationInfoDatabaseHandler.class); + + /** + * Connection to the couchDB database + */ + private final DatabaseConnectorCloudant db; + private final DatabaseConnectorCloudant dbChangeLogs; + + private final SpdxDocumentCreationInfoRepository SPDXDocumentCreationInfoRepository; + private final SpdxDocumentRepository SPDXDocumentRepository; + private DatabaseHandlerUtil dbHandlerUtil; + private final SpdxDocumentCreationInfoModerator moderator; + + public SpdxDocumentCreationInfoDatabaseHandler(Supplier httpClient, String dbName) throws MalformedURLException { + db = new DatabaseConnectorCloudant(httpClient, dbName); + + // Create the repositories + SPDXDocumentCreationInfoRepository = new SpdxDocumentCreationInfoRepository(db); + SPDXDocumentRepository = new SpdxDocumentRepository(db); + // Create the moderator + moderator = new SpdxDocumentCreationInfoModerator(); + // Create the changelogs + dbChangeLogs = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_CHANGE_LOGS); + this.dbHandlerUtil = new DatabaseHandlerUtil(dbChangeLogs); + } + + public List getDocumentCreationInformationSummary(User user) { + List documentCreationInfos = SPDXDocumentCreationInfoRepository.getDocumentCreationInformationSummary(); + return documentCreationInfos; + } + + public DocumentCreationInformation getDocumentCreationInformationById(String id, User user) throws SW360Exception { + DocumentCreationInformation documentCreationInfo = SPDXDocumentCreationInfoRepository.get(id); + assertNotNull(documentCreationInfo, "Could not find SPDX Document Creation Info by id: " + id); + // Set permissions + if (user != null) { + makePermission(documentCreationInfo, user).fillPermissions(); + } + return documentCreationInfo; + } + + public DocumentCreationInformation getDocumentCreationInfoForEdit(String id, User user) throws SW360Exception { + List moderationRequestsForDocumentId = moderator.getModerationRequestsForDocumentId(id); + + DocumentCreationInformation documentCreationInfo = getDocumentCreationInformationById(id, user); + DocumentState documentState; + + if (moderationRequestsForDocumentId.isEmpty()) { + documentState = CommonUtils.getOriginalDocumentState(); + } else { + final String email = user.getEmail(); + Optional moderationRequestOptional = CommonUtils.getFirstModerationRequestOfUser(moderationRequestsForDocumentId, email); + if (moderationRequestOptional.isPresent() + && isInProgressOrPending(moderationRequestOptional.get())){ + ModerationRequest moderationRequest = moderationRequestOptional.get(); + documentCreationInfo = moderator.updateSpdxDocumentCreationInfoFromModerationRequest(documentCreationInfo, moderationRequest.getDocumentCreationInfoAdditions(), moderationRequest.getDocumentCreationInfoDeletions()); + documentState = CommonUtils.getModeratedDocumentState(moderationRequest); + } else { + documentState = new DocumentState().setIsOriginalDocument(true).setModerationState(moderationRequestsForDocumentId.get(0).getModerationState()); + } + } + documentCreationInfo.setPermissions(makePermission(documentCreationInfo, user).getPermissionMap()); + documentCreationInfo.setDocumentState(documentState); + return documentCreationInfo; + } + + public AddDocumentRequestSummary addDocumentCreationInformation(DocumentCreationInformation documentCreationInfo, User user) throws SW360Exception { + AddDocumentRequestSummary requestSummary= new AddDocumentRequestSummary(); + prepareSpdxDocumentCreationInfo(documentCreationInfo); + String spdxDocumentId = documentCreationInfo.getSpdxDocumentId(); + SPDXDocument spdxDocument = SPDXDocumentRepository.get(spdxDocumentId); + assertNotNull(spdxDocument, "Could not find SPDX Document to add SPDX Document Creation Info!"); + if (isNotNullEmptyOrWhitespace(spdxDocument.getSpdxDocumentCreationInfoId())) { + log.error("SPDX Document Creation existed in SPDX Document!"); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.DUPLICATE) + .setId(spdxDocumentId); + } + documentCreationInfo.setCreatedBy(user.getEmail()); + SPDXDocumentCreationInfoRepository.add(documentCreationInfo); + String documentCreationInfoId = documentCreationInfo.getId(); + spdxDocument.setSpdxDocumentCreationInfoId(documentCreationInfoId); + SPDXDocumentRepository.update(spdxDocument); + dbHandlerUtil.addChangeLogs(documentCreationInfo, null, user.getEmail(), Operation.CREATE, null, Lists.newArrayList(), null, null); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.SUCCESS) + .setId(documentCreationInfoId); + } + + public RequestStatus updateDocumentCreationInformation(DocumentCreationInformation documentCreationInfo, User user) throws SW360Exception { + DocumentCreationInformation actual = SPDXDocumentCreationInfoRepository.get(documentCreationInfo.getId()); + assertNotNull(actual, "Could not find SPDX Document Creation Information to update!"); + prepareSpdxDocumentCreationInfo(documentCreationInfo); + if (!makePermission(documentCreationInfo, user).isActionAllowed(RequestedAction.WRITE)) { + if (isChanged(actual, documentCreationInfo)) { + return moderator.updateSpdxDocumentCreationInfo(documentCreationInfo, user); + } else { + return RequestStatus.SUCCESS; + } + } + SPDXDocumentCreationInfoRepository.update(documentCreationInfo); + dbHandlerUtil.addChangeLogs(documentCreationInfo, actual, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), null, null); + return RequestStatus.SUCCESS; + } + + public RequestStatus updateDocumentCreationInfomationFromModerationRequest(DocumentCreationInformation documentCreationInfoAdditions, DocumentCreationInformation documentCreationInfoDeletions, User user) throws SW360Exception { + try { + DocumentCreationInformation documentCreationInfo = getDocumentCreationInformationById(documentCreationInfoAdditions.getId(), user); + documentCreationInfo = moderator.updateSpdxDocumentCreationInfoFromModerationRequest(documentCreationInfo, documentCreationInfoAdditions, documentCreationInfoDeletions); + return updateDocumentCreationInformation(documentCreationInfo, user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Document creation info when updating from moderation request."); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deleteDocumentCreationInformation(String id, User user) throws SW360Exception { + DocumentCreationInformation documentCreationInfo = SPDXDocumentCreationInfoRepository.get(id); + assertNotNull(documentCreationInfo, "Could not find SPDX Document Creation Information to delete!"); + if (!makePermission(documentCreationInfo, user).isActionAllowed(RequestedAction.WRITE)) { + return moderator.deleteSpdxDocumentCreationInfo(documentCreationInfo, user); + } + SPDXDocumentCreationInfoRepository.remove(documentCreationInfo); + String spdxDocumentId = documentCreationInfo.getSpdxDocumentId(); + if (isNotNullEmptyOrWhitespace(spdxDocumentId)) { + SPDXDocument spdxDocument = SPDXDocumentRepository.get(spdxDocumentId); + assertNotNull(spdxDocument, "Could not remove SPDX Document Creation Info ID in SPDX Document!"); + SPDXDocument oldSpdxDocument = spdxDocument.deepCopy(); + spdxDocument.unsetSpdxDocumentCreationInfoId(); + SPDXDocumentRepository.update(spdxDocument); + dbHandlerUtil.addChangeLogs(spdxDocument, oldSpdxDocument, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), documentCreationInfo.getId(), Operation.SPDX_DOCUMENT_CREATION_INFO_DELETE); + } + return RequestStatus.SUCCESS; + } + + private boolean isChanged(DocumentCreationInformation actual, DocumentCreationInformation update) { + + for (DocumentCreationInformation._Fields field : DocumentCreationInformation._Fields.values()) { + if(update.getFieldValue(field) == null) { + continue; + } else if (actual.getFieldValue(field) == null) { + return true; + } else if (!actual.getFieldValue(field).equals(update.getFieldValue(field))) { + return true; + } + } + + return false; + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoRepository.java new file mode 100644 index 0000000000..bcfe7e0691 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo; + +import org.eclipse.sw360.components.summary.DocumentCreationInformationSummary; +import org.eclipse.sw360.components.summary.SummaryType; +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.couchdb.SummaryAwareRepository; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; + +import com.cloudant.client.api.model.DesignDocument.MapReduce; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SpdxDocumentCreationInfoRepository extends SummaryAwareRepository { + + private static final String ALL = "function(doc) { if (doc.type == 'documentCreationInformation') emit(null, doc._id) }"; + + public SpdxDocumentCreationInfoRepository(DatabaseConnectorCloudant db) { + super(DocumentCreationInformation.class, db, new DocumentCreationInformationSummary()); + Map views = new HashMap(); + views.put("all", createMapReduce(ALL, null)); + initStandardDesignDocument(views, db); + } + + public List getDocumentCreationInformationSummary() { + return makeSummary(SummaryType.SUMMARY, getAllIds()); + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoSearchHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoSearchHandler.java new file mode 100644 index 0000000000..d863e38f6f --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoSearchHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo; + +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector; +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneSearchView; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.ektorp.http.HttpClient; + +import com.cloudant.client.api.CloudantClient; + +import java.io.IOException; +import java.util.List; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector.prepareWildcardQuery; + +public class SpdxDocumentCreationInfoSearchHandler { + + private static final LuceneSearchView luceneSearchView + = new LuceneSearchView("lucene", "documentCreationInformation", + "function(doc) {" + + " if(doc.type == 'documentCreationInformation') { " + + " var ret = new Document();" + + " ret.add(doc._id); " + + " return ret;" + + " }" + + "}"); + + private final LuceneAwareDatabaseConnector connector; + + public SpdxDocumentCreationInfoSearchHandler(Supplier httpClient, Supplier cClient, String dbName) throws IOException { + connector = new LuceneAwareDatabaseConnector(httpClient, cClient, dbName); + connector.addView(luceneSearchView); + } + + public List search(String searchText) { + return connector.searchView(DocumentCreationInformation.class, luceneSearchView, prepareWildcardQuery(searchText)); + } +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoDatabaseHandler.java new file mode 100644 index 0000000000..48e0fff097 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoDatabaseHandler.java @@ -0,0 +1,245 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.packageinfo; + +import com.cloudant.client.api.CloudantClient; + +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentRepository; +import org.eclipse.sw360.datahandler.thrift.*; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.eclipse.sw360.datahandler.thrift.changelogs.*; +import org.eclipse.sw360.datahandler.db.DatabaseHandlerUtil; +import org.eclipse.sw360.datahandler.entitlement.SpdxPackageInfoModerator; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; +import org.eclipse.sw360.datahandler.common.CommonUtils; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +import java.net.MalformedURLException; +import java.util.*; +import java.util.function.Supplier; +import com.google.common.collect.Lists; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import static org.eclipse.sw360.datahandler.common.CommonUtils.*; +import static org.eclipse.sw360.datahandler.common.SW360Assert.assertNotNull; +import static org.eclipse.sw360.datahandler.permissions.PermissionUtils.makePermission; +import static org.eclipse.sw360.datahandler.thrift.ThriftValidate.prepareSpdxPackageInfo; + +public class SpdxPackageInfoDatabaseHandler { + + private static final Logger log = LogManager.getLogger(SpdxPackageInfoDatabaseHandler.class); + private final DatabaseConnectorCloudant dbChangeLogs; + + /** + * Connection to the couchDB database + */ + private final DatabaseConnectorCloudant db; + + private final SpdxPackageInfoRepository PackageInfoRepository; + private final SpdxDocumentRepository SPDXDocumentRepository; + private DatabaseHandlerUtil dbHandlerUtil; + private final SpdxPackageInfoModerator moderator; + + public SpdxPackageInfoDatabaseHandler(Supplier httpClient, String dbName) throws MalformedURLException { + db = new DatabaseConnectorCloudant(httpClient, dbName); + + // Create the repositories + PackageInfoRepository = new SpdxPackageInfoRepository(db); + SPDXDocumentRepository = new SpdxDocumentRepository(db); + + // Create the moderator + moderator = new SpdxPackageInfoModerator(); + // Create the changelogs + dbChangeLogs = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_CHANGE_LOGS); + this.dbHandlerUtil = new DatabaseHandlerUtil(dbChangeLogs); + } + + public List getPackageInformationSummary(User user) { + List packageInfos = PackageInfoRepository.getPackageInformationSummary(); + return packageInfos; + } + + public PackageInformation getPackageInformationById(String id, User user) throws SW360Exception { + PackageInformation packageInfo = PackageInfoRepository.get(id); + assertNotNull(packageInfo, "Could not find SPDX Package Info by id: " + id); + // Set permissions + if (user != null) { + makePermission(packageInfo, user).fillPermissions(); + } + return packageInfo; + } + + public PackageInformation getPackageInformationForEdit(String id, User user) throws SW360Exception { + List moderationRequestsForDocumentId = moderator.getModerationRequestsForDocumentId(id); + + PackageInformation packageInfo = getPackageInformationById(id, user); + DocumentState documentState; + + if (moderationRequestsForDocumentId.isEmpty()) { + documentState = CommonUtils.getOriginalDocumentState(); + } else { + final String email = user.getEmail(); + Optional moderationRequestOptional = CommonUtils.getFirstModerationRequestOfUser(moderationRequestsForDocumentId, email); + if (moderationRequestOptional.isPresent() + && isInProgressOrPending(moderationRequestOptional.get())){ + ModerationRequest moderationRequest = moderationRequestOptional.get(); + packageInfo = moderator.updateSpdxPackageInfoFromModerationRequest(packageInfo, moderationRequest.getPackageInfoAdditions(), moderationRequest.getPackageInfoDeletions()); + documentState = CommonUtils.getModeratedDocumentState(moderationRequest); + } else { + documentState = new DocumentState().setIsOriginalDocument(true).setModerationState(moderationRequestsForDocumentId.get(0).getModerationState()); + } + } + packageInfo.setPermissions(makePermission(packageInfo, user).getPermissionMap()); + packageInfo.setDocumentState(documentState); + return packageInfo; + } + + public AddDocumentRequestSummary addPackageInformation(PackageInformation packageInfo, User user) throws SW360Exception { + AddDocumentRequestSummary requestSummary = new AddDocumentRequestSummary(); + prepareSpdxPackageInfo(packageInfo); + packageInfo.setCreatedBy(user.getEmail()); + PackageInfoRepository.add(packageInfo); + String packageInfoId = packageInfo.getId(); + String spdxDocumentId = packageInfo.getSpdxDocumentId(); + SPDXDocument spdxDocument = SPDXDocumentRepository.get(spdxDocumentId); + assertNotNull(spdxDocument, "Could not find SPDX Document by id: " + spdxDocumentId); + Set spdxPackageInfoIds = new HashSet<>(); + if (spdxDocument.getSpdxPackageInfoIds() != null) { + spdxPackageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + } + spdxPackageInfoIds.add(packageInfoId); + spdxDocument.setSpdxPackageInfoIds(spdxPackageInfoIds); + SPDXDocumentRepository.update(spdxDocument); + dbHandlerUtil.addChangeLogs(packageInfo, null, user.getEmail(), Operation.CREATE, null, Lists.newArrayList(), null, null); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.SUCCESS).setId(packageInfoId); + } + + public AddDocumentRequestSummary addPackageInformations(Set packageInfos, User user) throws SW360Exception { + AddDocumentRequestSummary requestSummary = new AddDocumentRequestSummary(); + String spdxDocumentId = packageInfos.iterator().next().getSpdxDocumentId(); + SPDXDocument spdxDocument = SPDXDocumentRepository.get(spdxDocumentId); + assertNotNull(spdxDocument, "Could not find SPDX Document by id: " + spdxDocumentId); + Set packageInfoIds = new HashSet<>(); + if (spdxDocument.getSpdxPackageInfoIds() != null) { + packageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + } + for (PackageInformation packageInfo : packageInfos) { + prepareSpdxPackageInfo(packageInfo); + packageInfo.setCreatedBy(user.getEmail()); + PackageInfoRepository.add(packageInfo); + packageInfoIds.add(packageInfo.getId()); + dbHandlerUtil.addChangeLogs(packageInfo, null, user.getEmail(), Operation.CREATE, null, Lists.newArrayList(), null, null); + } + spdxDocument.setSpdxPackageInfoIds(packageInfoIds); + SPDXDocumentRepository.update(spdxDocument); + return requestSummary.setRequestStatus(AddDocumentRequestStatus.SUCCESS).setId(spdxDocumentId); + } + + public RequestStatus updatePackageInformation(PackageInformation packageInfo, User user) throws SW360Exception { + prepareSpdxPackageInfo(packageInfo); + PackageInformation actual = PackageInfoRepository.get(packageInfo.getId()); + assertNotNull(actual, "Could not find SPDX Package Information to update!"); + if (!makePermission(packageInfo, user).isActionAllowed(RequestedAction.WRITE)) { + if (isChanged(actual, packageInfo)) { + return moderator.updateSpdxPackageInfo(packageInfo, user); + } else { + return RequestStatus.SUCCESS; + } + } + PackageInfoRepository.update(packageInfo); + dbHandlerUtil.addChangeLogs(packageInfo, actual, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), null, null); + return RequestStatus.SUCCESS; + } + + public RequestSummary updatePackageInformations(Set packageInfos, User user) throws SW360Exception { + int countPackagesSendToModerator = 0; + for (PackageInformation packageInfo : packageInfos) { + PackageInformation actual = PackageInfoRepository.get(packageInfo.getId()); + assertNotNull(actual, "Could not find SPDX Package Information to update!"); + prepareSpdxPackageInfo(packageInfo); + if (!makePermission(packageInfos, user).isActionAllowed(RequestedAction.WRITE)) { + if (moderator.updateSpdxPackageInfo(packageInfo, user) == RequestStatus.SENT_TO_MODERATOR) { + countPackagesSendToModerator++; + } + } else { + PackageInfoRepository.update(packageInfo); + dbHandlerUtil.addChangeLogs(packageInfo, actual, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), null, null); + } + } + RequestSummary requestSummary = new RequestSummary(); + if (countPackagesSendToModerator == packageInfos.size()) { + requestSummary.setRequestStatus(RequestStatus.SENT_TO_MODERATOR); + } else { + String message = "Send to moderator request " + countPackagesSendToModerator; + requestSummary.setMessage(message) + .setTotalAffectedElements(countPackagesSendToModerator) + .setTotalElements(packageInfos.size()) + .setRequestStatus(RequestStatus.SUCCESS); + } + return requestSummary; + } + + public RequestStatus updatePackageInfomationFromModerationRequest(PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions, User user) throws SW360Exception { + try { + PackageInformation packageInformation = getPackageInformationById(packageInfoAdditions.getId(), user); + packageInformation = moderator.updateSpdxPackageInfoFromModerationRequest(packageInformation, packageInfoAdditions, packageInfoDeletions); + return updatePackageInformation(packageInformation, user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Package info when updating from moderation request."); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deletePackageInformation(String id, User user) throws SW360Exception { + PackageInformation packageInfo = PackageInfoRepository.get(id); + assertNotNull(packageInfo, "Could not find SPDX Package Information to delete!"); + if (!makePermission(packageInfo, user).isActionAllowed(RequestedAction.WRITE)) { + return moderator.deleteSpdxPackageInfo(packageInfo, user); + } + PackageInfoRepository.remove(packageInfo); + String spdxDocumentId = packageInfo.getSpdxDocumentId(); + SPDXDocument spdxDocument = SPDXDocumentRepository.get(spdxDocumentId); + assertNotNull(spdxDocument, "Could not find SPDX Document to remove Package Info!"); + SPDXDocument oldSpdxDocument = spdxDocument.deepCopy(); + Set packageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + if (packageInfoIds != null) { + packageInfoIds.remove(id); + spdxDocument.setSpdxPackageInfoIds(packageInfoIds); + SPDXDocumentRepository.update(spdxDocument); + dbHandlerUtil.addChangeLogs(spdxDocument, oldSpdxDocument, user.getEmail(), Operation.UPDATE, null, Lists.newArrayList(), packageInfo.getId(), Operation.SPDX_PACKAGE_INFO_DELETE); + } else { + log.warn("Could not remove Package Id from SPDX Documnet"); + } + + return RequestStatus.SUCCESS; + } + + private boolean isChanged(PackageInformation actual, PackageInformation update) { + + for (PackageInformation._Fields field : PackageInformation._Fields.values()) { + if(update.getFieldValue(field) == null) { + continue; + } else if (actual.getFieldValue(field) == null) { + return true; + } else if (!actual.getFieldValue(field).equals(update.getFieldValue(field))) { + return true; + } + } + + return false; + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoRepository.java new file mode 100644 index 0000000000..1bfeb2bf6a --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.packageinfo; + +import org.eclipse.sw360.components.summary.PackageInformationSummary; +import org.eclipse.sw360.components.summary.SummaryType; +import org.eclipse.sw360.datahandler.cloudantclient.DatabaseConnectorCloudant; +import org.eclipse.sw360.datahandler.couchdb.SummaryAwareRepository; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; + +import com.cloudant.client.api.model.DesignDocument.MapReduce; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SpdxPackageInfoRepository extends SummaryAwareRepository { + + private static final String ALL = "function(doc) { if (doc.type == 'packageInformation') emit(null, doc._id) }"; + + public SpdxPackageInfoRepository(DatabaseConnectorCloudant db) { + super(PackageInformation.class, db, new PackageInformationSummary()); + Map views = new HashMap(); + views.put("all", createMapReduce(ALL, null)); + initStandardDesignDocument(views, db); + } + + public List getPackageInformationSummary() { + return makeSummary(SummaryType.SUMMARY, getAllIds()); + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoSearchHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoSearchHandler.java new file mode 100644 index 0000000000..70b5b2d61f --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoSearchHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.db.spdx.packageinfo; + +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector; +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneSearchView; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.ektorp.http.HttpClient; + +import com.cloudant.client.api.CloudantClient; + +import java.io.IOException; +import java.util.List; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector.prepareWildcardQuery; + +public class SpdxPackageInfoSearchHandler { + + private static final LuceneSearchView luceneSearchView + = new LuceneSearchView("lucene", "packageInformation", + "function(doc) {" + + " if(doc.type == 'packageInformation') { " + + " var ret = new Document();" + + " ret.add(doc._id); " + + " return ret;" + + " }" + + "}"); + + private final LuceneAwareDatabaseConnector connector; + + public SpdxPackageInfoSearchHandler(Supplier httpClient, Supplier cClient, String dbName) throws IOException { + connector = new LuceneAwareDatabaseConnector(httpClient, cClient, dbName); + connector.addView(luceneSearchView); + } + + public List search(String searchText) { + return connector.searchView(PackageInformation.class, luceneSearchView, prepareWildcardQuery(searchText)); + } +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentCreationInfoModerator.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentCreationInfoModerator.java new file mode 100644 index 0000000000..3335a5c5bc --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentCreationInfoModerator.java @@ -0,0 +1,156 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.entitlement; + +import org.eclipse.sw360.datahandler.common.Moderator; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.ThriftClients; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.Creator; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.ExternalDocumentReferences; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.apache.logging.log4j.Logger; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.thrift.TException; + +public class SpdxDocumentCreationInfoModerator + extends Moderator { + + private static final Logger log = LogManager.getLogger(SpdxDocumentCreationInfoModerator.class); + + public SpdxDocumentCreationInfoModerator(ThriftClients thriftClients) { + super(thriftClients); + } + + public SpdxDocumentCreationInfoModerator() { + super(new ThriftClients()); + } + + public RequestStatus updateSpdxDocumentCreationInfo(DocumentCreationInformation documentCreationInfo, User user) { + + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSpdxDocumentCreationInfoRequest(documentCreationInfo, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate SPDX Document Creation Info " + documentCreationInfo.getId() + " for User " + + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deleteSpdxDocumentCreationInfo(DocumentCreationInformation documentCreationInfo, User user) { + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSpdxDocumentCreationInfoDeleteRequest(documentCreationInfo, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate delete SPDX document creation information" + documentCreationInfo.getId() + " for User " + + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public DocumentCreationInformation updateSpdxDocumentCreationInfoFromModerationRequest( + DocumentCreationInformation documentCreationInfo, DocumentCreationInformation documentCreationInfoAdditions, + DocumentCreationInformation documentCreationInfoDeletions) { + for (DocumentCreationInformation._Fields field : DocumentCreationInformation._Fields.values()) { + if (documentCreationInfoAdditions.getFieldValue(field) == null + && documentCreationInfoDeletions.getFieldValue(field) == null) { + continue; + } + switch (field) { + case ID: + case REVISION: + case TYPE: + break; + case EXTERNAL_DOCUMENT_REFS: + documentCreationInfo = updateExternalDocumentRefs(documentCreationInfo, documentCreationInfoAdditions, documentCreationInfoDeletions); + break; + case CREATOR: + documentCreationInfo = updateCreator(documentCreationInfo, documentCreationInfoAdditions, documentCreationInfoDeletions); + break; + default: + documentCreationInfo = updateBasicField(field, DocumentCreationInformation.metaDataMap.get(field), + documentCreationInfo, documentCreationInfoAdditions, documentCreationInfoDeletions); + } + + } + return documentCreationInfo; + } + + private DocumentCreationInformation updateExternalDocumentRefs(DocumentCreationInformation documentCreationInfo, + DocumentCreationInformation documentCreationInfoAdditions, + DocumentCreationInformation documentCreationInfoDeletions) { + Set actuals = documentCreationInfo.getExternalDocumentRefs(); + Iterator additionsIterator = documentCreationInfoAdditions.getExternalDocumentRefsIterator(); + Iterator deletionsIterator = documentCreationInfoDeletions.getExternalDocumentRefsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return documentCreationInfo; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + ExternalDocumentReferences additions = additionsIterator.next(); + ExternalDocumentReferences actual = new ExternalDocumentReferences(); + for (ExternalDocumentReferences._Fields field : ExternalDocumentReferences._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + ExternalDocumentReferences deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + documentCreationInfo.setExternalDocumentRefs(actuals); + return documentCreationInfo; + } + + private DocumentCreationInformation updateCreator(DocumentCreationInformation documentCreationInfo, + DocumentCreationInformation documentCreationInfoAdditions, + DocumentCreationInformation documentCreationInfoDeletions) { + Set actuals = documentCreationInfo.getCreator(); + Iterator additionsIterator = documentCreationInfoAdditions.getCreatorIterator(); + Iterator deletionsIterator = documentCreationInfoDeletions.getCreatorIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return documentCreationInfo; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + Creator additions = additionsIterator.next(); + Creator actual = new Creator(); + for (Creator._Fields field : Creator._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + Creator deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + documentCreationInfo.setCreator(actuals); + return documentCreationInfo; + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentModerator.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentModerator.java new file mode 100644 index 0000000000..50f179ab6c --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentModerator.java @@ -0,0 +1,210 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.entitlement; + +import org.eclipse.sw360.datahandler.common.Moderator; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.ThriftClients; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.apache.logging.log4j.Logger; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.thrift.TException; + +public class SpdxDocumentModerator extends Moderator { + + private static final Logger log = LogManager.getLogger(SpdxDocumentModerator.class); + + public SpdxDocumentModerator(ThriftClients thriftClients) { + super(thriftClients); + } + + public SpdxDocumentModerator() { + super(new ThriftClients()); + } + + public RequestStatus updateSPDXDocument(SPDXDocument spdx, User user) { + + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSPDXDocumentRequest(spdx, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate SPDX Document " + spdx.getId() + " for User " + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deleteSPDXDocument(SPDXDocument spdx, User user) { + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSPDXDocumentDeleteRequest(spdx, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate delete SPDX document " + spdx.getId() + " for User " + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public SPDXDocument updateSPDXDocumentFromModerationRequest(SPDXDocument spdx, SPDXDocument spdxAdditions, SPDXDocument spdxDeletions) { + for (SPDXDocument._Fields field : SPDXDocument._Fields.values()) { + if(spdxAdditions.getFieldValue(field) == null && spdxDeletions.getFieldValue(field) == null) { + continue; + } + switch (field) { + case ID: + case REVISION: + case TYPE: + break; + case OTHER_LICENSING_INFORMATION_DETECTEDS: + spdx = updateOtherLicensingInformationDetecteds(spdx, spdxAdditions, spdxDeletions); + break; + case RELATIONSHIPS: + spdx = updateRelationships(spdx, spdxAdditions, spdxDeletions); + break; + case ANNOTATIONS: + spdx = updateAnnotaions(spdx, spdxAdditions, spdxDeletions); + break; + case SNIPPETS: + spdx = updateSnippets(spdx, spdxAdditions, spdxDeletions); + break; + default: + spdx = updateBasicField(field, SPDXDocument.metaDataMap.get(field), spdx, spdxAdditions, spdxDeletions); + } + + } + return spdx; + } + + private SPDXDocument updateOtherLicensingInformationDetecteds(SPDXDocument spdx, SPDXDocument spdxAdditions, SPDXDocument spdxDeletions) { + Set actuals = spdx.getOtherLicensingInformationDetecteds(); + Iterator additionsIterator = spdxAdditions.getOtherLicensingInformationDetectedsIterator(); + Iterator deletionsIterator = spdxDeletions.getOtherLicensingInformationDetectedsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return spdx; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + OtherLicensingInformationDetected additions = additionsIterator.next(); + OtherLicensingInformationDetected actual = new OtherLicensingInformationDetected(); + for (OtherLicensingInformationDetected._Fields field : OtherLicensingInformationDetected._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while(deletionsIterator.hasNext()) { + OtherLicensingInformationDetected deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + + spdx.setOtherLicensingInformationDetecteds(actuals); + return spdx; + } + + private SPDXDocument updateRelationships(SPDXDocument spdx, SPDXDocument spdxAdditions, SPDXDocument spdxDeletions) { + Set actuals = spdx.getRelationships(); + Iterator additionsIterator = spdxAdditions.getRelationshipsIterator(); + Iterator deletionsIterator = spdxDeletions.getRelationshipsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return spdx; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + RelationshipsBetweenSPDXElements additions = additionsIterator.next(); + RelationshipsBetweenSPDXElements actual = new RelationshipsBetweenSPDXElements(); + for (RelationshipsBetweenSPDXElements._Fields field : RelationshipsBetweenSPDXElements._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + RelationshipsBetweenSPDXElements deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + spdx.setRelationships(actuals); + return spdx; + } + + private SPDXDocument updateAnnotaions(SPDXDocument spdx, SPDXDocument spdxAdditions, SPDXDocument spdxDeletions) { + Set actuals = spdx.getAnnotations(); + Iterator additionsIterator = spdxAdditions.getAnnotationsIterator(); + Iterator deletionsIterator = spdxDeletions.getAnnotationsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return spdx; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + Annotations additions = additionsIterator.next(); + Annotations actual = new Annotations(); + for (Annotations._Fields field : Annotations._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + Annotations deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + spdx.setAnnotations(actuals); + return spdx; + } + + private SPDXDocument updateSnippets(SPDXDocument spdx, SPDXDocument spdxAdditions, SPDXDocument spdxDeletions) { + Set actuals = spdx.getSnippets(); + Iterator additionsIterator = spdxAdditions.getSnippetsIterator(); + Iterator deletionsIterator = spdxDeletions.getSnippetsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return spdx; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + SnippetInformation additions = additionsIterator.next(); + SnippetInformation actual = new SnippetInformation(); + for (SnippetInformation._Fields field : SnippetInformation._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + SnippetInformation deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + spdx.setSnippets(actuals); + return spdx; + } + +} \ No newline at end of file diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxPackageInfoModerator.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxPackageInfoModerator.java new file mode 100644 index 0000000000..e45be7e79b --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxPackageInfoModerator.java @@ -0,0 +1,207 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.entitlement; + +import org.eclipse.sw360.datahandler.common.Moderator; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.ThriftClients; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.CheckSum; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import org.apache.logging.log4j.Logger; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.thrift.TException; + +public class SpdxPackageInfoModerator extends Moderator { + + private static final Logger log = LogManager.getLogger(SpdxPackageInfoModerator.class); + + + public SpdxPackageInfoModerator(ThriftClients thriftClients) { + super(thriftClients); + } + + public SpdxPackageInfoModerator() { + super(new ThriftClients()); + } + + public RequestStatus updateSpdxPackageInfo(PackageInformation packageInfo, User user) { + + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSpdxPackageInfoRequest(packageInfo, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate SPDX Package Info " + packageInfo.getId() + " for User " + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public RequestStatus deleteSpdxPackageInfo(PackageInformation packageInfo, User user) { + try { + ModerationService.Iface client = thriftClients.makeModerationClient(); + client.createSpdxPackageInfoDeleteRequest(packageInfo, user); + return RequestStatus.SENT_TO_MODERATOR; + } catch (TException e) { + log.error("Could not moderate delete SPDX document " + packageInfo.getId() + " for User " + user.getEmail(), e); + return RequestStatus.FAILURE; + } + } + + public PackageInformation updateSpdxPackageInfoFromModerationRequest(PackageInformation packageInfo, + PackageInformation packageInfoAdditions, + PackageInformation packageInfoDeletions) { + for (PackageInformation._Fields field : PackageInformation._Fields.values()) { + if(packageInfoAdditions.getFieldValue(field) == null && packageInfoDeletions.getFieldValue(field) == null){ + continue; + } + switch (field) { + case ID: + case REVISION: + case TYPE: + break; + case CHECKSUMS: + packageInfo = updateCheckSums(packageInfo, packageInfoAdditions, packageInfoDeletions); + break; + case EXTERNAL_REFS: + packageInfo = updateExternalReference(packageInfo, packageInfoAdditions, packageInfoDeletions); + break; + case ANNOTATIONS: + packageInfo = updateAnnotaions(packageInfo, packageInfoAdditions, packageInfoDeletions); + break; + case PACKAGE_VERIFICATION_CODE: + packageInfo = updatePackageVerificationCode(packageInfo, packageInfoAdditions, packageInfoDeletions); + break; + default: + packageInfo = updateBasicField(field, PackageInformation.metaDataMap.get(field), packageInfo, packageInfoAdditions, packageInfoDeletions); + } + + } + return packageInfo; + } + + private PackageInformation updateAnnotaions(PackageInformation packageInfo, PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions) { + Set actuals = packageInfo.getAnnotations(); + Iterator additionsIterator = packageInfoAdditions.getAnnotationsIterator(); + Iterator deletionsIterator = packageInfoDeletions.getAnnotationsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return packageInfo; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + Annotations additions = additionsIterator.next(); + Annotations actual = new Annotations(); + for (Annotations._Fields field : Annotations._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + Annotations deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + packageInfo.setAnnotations(actuals); + return packageInfo; + } + + private PackageInformation updateCheckSums(PackageInformation packageInfo, PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions) { + Set actuals = packageInfo.getChecksums(); + Iterator additionsIterator = packageInfoAdditions.getChecksumsIterator(); + Iterator deletionsIterator = packageInfoDeletions.getChecksumsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return packageInfo; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + CheckSum additions = additionsIterator.next(); + CheckSum actual = new CheckSum(); + for (CheckSum._Fields field : CheckSum._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + CheckSum deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + packageInfo.setChecksums(actuals); + return packageInfo; + } + + private PackageInformation updateExternalReference(PackageInformation packageInfo, PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions) { + Set actuals = packageInfo.getExternalRefs(); + Iterator additionsIterator = packageInfoAdditions.getExternalRefsIterator(); + Iterator deletionsIterator = packageInfoDeletions.getExternalRefsIterator(); + if (additionsIterator == null && deletionsIterator == null) { + return packageInfo; + } + if (actuals == null) { + actuals = new HashSet<>(); + } + while (additionsIterator.hasNext()) { + ExternalReference additions = additionsIterator.next(); + ExternalReference actual = new ExternalReference(); + for (ExternalReference._Fields field : ExternalReference._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + actuals.add(actual); + } + while (deletionsIterator.hasNext()) { + ExternalReference deletions = deletionsIterator.next(); + actuals.remove(deletions); + } + packageInfo.setExternalRefs(actuals); + return packageInfo; + } + + private PackageInformation updatePackageVerificationCode(PackageInformation packageInfo, PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions) { + PackageVerificationCode actual = packageInfo.getPackageVerificationCode(); + PackageVerificationCode additions = packageInfoAdditions.getPackageVerificationCode(); + PackageVerificationCode deletions = packageInfoDeletions.getPackageVerificationCode(); + + if (additions == null && deletions == null) { + return packageInfo; + } + if (actual == null) { + actual = new PackageVerificationCode(); + } + + for (PackageVerificationCode._Fields field : PackageVerificationCode._Fields.values()) { + if (additions.isSet(field)) { + actual.setFieldValue(field, additions.getFieldValue(field)); + } + } + + packageInfo.setPackageVerificationCode(actual); + return packageInfo; + } + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporter.java b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporter.java new file mode 100644 index 0000000000..61d25a55d0 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporter.java @@ -0,0 +1,281 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdx; + +import org.eclipse.sw360.datahandler.thrift.*; +import org.eclipse.sw360.datahandler.thrift.components.Release; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.*; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.*; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.*; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.spdx.rdfparser.InvalidSPDXAnalysisException; +import org.spdx.rdfparser.license.ExtractedLicenseInfo; +import org.spdx.tools.SpdxConverter; +import org.spdx.tools.SpdxConverterException; +import org.spdx.tools.RdfToTag; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.util.*; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForSPDXDocument.*; +public class SpdxBOMExporter { + private static final Logger log = LogManager.getLogger(SpdxBOMExporter.class); + private final SpdxBOMExporterSink sink; + private Set licenses = new HashSet<>(); + + public SpdxBOMExporter(SpdxBOMExporterSink sink) { + this.sink = sink; + } + + public RequestSummary exportSPDXFile(String releaseId, String outputFormat) throws SW360Exception, MalformedURLException, InvalidSPDXAnalysisException { + RequestSummary requestSummary = new RequestSummary(); + String verifyMessage = ""; + final String targetFileName = releaseId + "." + outputFormat.toLowerCase(); + log.info("Export to file: " + targetFileName); + + if (createSPDXJsonFomatFromSW360SPDX(releaseId)) { + if (outputFormat.equals("JSON")) { + //verifyMessage = convertJSONtoOutputFormat(targetFileName, releaseId + ".RDF"); + requestSummary.setMessage("Export to JSON format successfully !"); + return requestSummary.setRequestStatus(RequestStatus.SUCCESS); + } else { + verifyMessage = convertJSONtoOutputFormat(releaseId + ".json", targetFileName); + if (verifyMessage.isEmpty()) { + log.info("Export to " + targetFileName + " sucessfully"); + requestSummary.setMessage("Export to " + outputFormat + " format successfully !"); + return requestSummary.setRequestStatus(RequestStatus.SUCCESS); + } else { + log.error("Export to " + targetFileName + " error"); + requestSummary.setMessage(verifyMessage); + return requestSummary.setRequestStatus(RequestStatus.FAILURE); + } + } + } else { + log.error("Export to " + targetFileName + " error !!!"); + requestSummary.setMessage("Export to " + targetFileName + " error !!!"); + return requestSummary.setRequestStatus(RequestStatus.FAILURE); + } + } + + private String convertJSONtoOutputFormat(String jsonFileName, String outputFileName ) { + try { + log.info("Convert " + jsonFileName + " to " + outputFileName); + if (outputFileName.split("\\.")[1].equals("spdx")) { + SpdxConverter.convert(jsonFileName, "tmp.rdf"); + RdfToTag.main(new String[] {"tmp.rdf", outputFileName}); + } else { + SpdxConverter.convert(jsonFileName, outputFileName); + } + } catch (SpdxConverterException e) { + log.error("Convert to " + outputFileName + " file error !!!"); + e.printStackTrace(); + return e.getMessage(); + } + return ""; + } + + private boolean createSPDXJsonFomatFromSW360SPDX(String releaseId) throws SW360Exception { + final SPDXDocument sw360SPDXDocument = getSpdxDocumentFromRelease(releaseId); + final Set sw360PackageInformations = getPackagesInformationFromSpdxDocument(sw360SPDXDocument.getId()); + final DocumentCreationInformation sw360CreationInfo = getDocCreationInfoFromSpdxDocument(sw360SPDXDocument.getId()); + + // creating JSONObject + JSONObject SPDXJson = new JSONObject(); + Map m = new LinkedHashMap<>(); + JSONParser parser = new JSONParser(); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.addMixInAnnotations(Annotations.class, AnnotationsMixin.class); + objectMapper.addMixInAnnotations(CheckSum.class, CheckSumMixin.class); + objectMapper.addMixInAnnotations(ExternalReference.class, ExternalReferenceMixin.class); + objectMapper.addMixInAnnotations(PackageInformation.class, PackageInformationMixin.class); + objectMapper.addMixInAnnotations(ExternalDocumentReferences.class, ExternalDocumentReferencesMixin.class); + objectMapper.addMixInAnnotations(SnippetInformation.class, SnippetInformationMixin.class); + objectMapper.addMixInAnnotations(SnippetRange.class, SnippetRangeMixin.class); + objectMapper.addMixInAnnotations(RelationshipsBetweenSPDXElements.class, RelationshipsBetweenSPDXElementsMixin.class); + objectMapper.addMixInAnnotations(OtherLicensingInformationDetected.class, OtherLicensingInformationDetectedMixin.class); + objectMapper.addMixInAnnotations(PackageVerificationCode.class, PackageVerificationCodeMixin.class); + + try { + // put package infomation to SPDX json + JSONArray SPDXPackageInfo = new JSONArray(); + JSONArray SDPXRelationships = (JSONArray) parser.parse(objectMapper.writeValueAsString(sw360SPDXDocument.getRelationships())); + for (PackageInformation sw360PackageInfo : sw360PackageInformations) { + log.info("Export Package Infomation: " + sw360PackageInfo.getName()); + JSONObject SW360SPDXPackageInfo = (JSONObject) parser.parse(objectMapper.writeValueAsString(sw360PackageInfo)); + + if (sw360PackageInfo.getPackageVerificationCode() != null) { + JSONObject packageVerificationCode = new JSONObject(); + JSONObject sw360packageVerificationCode = (JSONObject) parser.parse(objectMapper.writeValueAsString(sw360PackageInfo.getPackageVerificationCode())); + packageVerificationCode.put("packageVerificationCodeExcludedFiles", sw360packageVerificationCode.get("excludedFiles")); + packageVerificationCode.put("packageVerificationCodeValue", sw360packageVerificationCode.get("value")); + SW360SPDXPackageInfo.remove("packageVerificationCode"); + SW360SPDXPackageInfo.put("packageVerificationCode", packageVerificationCode); + } + + if (!sw360PackageInfo.getRelationships().isEmpty()) { + for (RelationshipsBetweenSPDXElements relationship : sw360PackageInfo.getRelationships()) { + JSONObject packageReleationship = (JSONObject) parser.parse(objectMapper.writeValueAsString(relationship)); + SDPXRelationships.add(packageReleationship); + } + } + + SW360SPDXPackageInfo.remove("relationships"); + SPDXPackageInfo.add(SW360SPDXPackageInfo); + } + SPDXJson.put("packages", SPDXPackageInfo); + + // put document creation infomation to SPDX json + JSONObject SW360SPDXCreationInfo = (JSONObject) parser.parse(objectMapper.writeValueAsString(sw360CreationInfo)); + Set keys = new HashSet<>(Arrays.asList("spdxVersion", "dataLicense", "SPDXID", "name", "documentNamespace", "externalDocumentRefs", + "documentComment")); + + for (String key : keys) { + if (key.equals("documentNamespace")) { + String documentNamespace = SW360SPDXCreationInfo.get(key).toString(); + if (documentNamespace.substring(documentNamespace.length() - 1).equals("#")) { + SPDXJson.put(key, documentNamespace.substring(0, documentNamespace.length() - 1)); + } else { + SPDXJson.put(key, documentNamespace); + } + } else { + SPDXJson.put(key, SW360SPDXCreationInfo.get(key)); + } + } + + JSONObject creationInfo = new JSONObject(); + creationInfo.put("comment", SW360SPDXCreationInfo.get("creatorComment")); + creationInfo.put("created", SW360SPDXCreationInfo.get("created")); + creationInfo.put("licenseListVersion", SW360SPDXCreationInfo.get("licenseListVersion")); + + JSONArray SW360SPDXCreationInfoCreator = (JSONArray) parser.parse(objectMapper.writeValueAsString(sw360CreationInfo.getCreator())); + JSONArray creators = new JSONArray(); + SW360SPDXCreationInfoCreator.forEach(c -> { + JSONObject obj = (JSONObject) c; + String type = (String) obj.get("type"); + String value = (String) obj.get("value"); + creators.add(type + ": " +value); + }); + creationInfo.put("creators", creators); + SPDXJson.put("creationInfo", creationInfo); + + + // put spdx document to SPDX json + JSONArray files = new JSONArray(); + for (SnippetInformation snippet : sw360SPDXDocument.getSnippets()) { + if (!snippet.getSnippetFromFile().isEmpty()) { + JSONObject file = new JSONObject(); + file.put("SPDXID", snippet.getSnippetFromFile()); + file.put("fileName", snippet.getSnippetFromFile()); + file.put("comment", "File information is generated from snippet and only SPDXID is correct information"); + files.add(file); + } + } + SPDXJson.put("files", files); + + JSONArray snippets = (JSONArray) parser.parse(objectMapper.writeValueAsString(sw360SPDXDocument.getSnippets())); + snippets.forEach(s -> { + JSONObject snippet = (JSONObject) s; + JSONArray ranges = new JSONArray(); + + JSONArray snippetRanges = (JSONArray) snippet.get("snippetRanges"); + snippetRanges.forEach(r -> { + JSONObject rangeElement = (JSONObject) r; + JSONObject range = new JSONObject(); + if (rangeElement.get("rangeType").equals("LINE")) { + JSONObject startPointer = new JSONObject(); + startPointer.put("lineNumber", rangeElement.get("startPointer")); + startPointer.put("reference", rangeElement.get("reference")); + range.put("startPointer", startPointer); + + JSONObject endPointer = new JSONObject(); + endPointer.put("lineNumber", rangeElement.get("endPointer")); + endPointer.put("reference", rangeElement.get("reference")); + range.put("endPointer", endPointer); + } else { + JSONObject startPointer = new JSONObject(); + startPointer.put("offset", rangeElement.get("startPointer")); + startPointer.put("reference", rangeElement.get("reference")); + range.put("startPointer", startPointer); + + JSONObject endPointer = new JSONObject(); + endPointer.put("offset", rangeElement.get("endPointer")); + endPointer.put("reference", rangeElement.get("reference")); + range.put("endPointer", endPointer); + } + ranges.add(range); + }); + snippet.remove("snippetRanges"); + snippet.put("ranges", ranges); + }); + SPDXJson.put("snippets", snippets); + + SPDXJson.put("relationships", SDPXRelationships); + SPDXJson.put("annotations", (JSONArray) parser.parse(objectMapper.writeValueAsString(sw360SPDXDocument.getAnnotations()))); + SPDXJson.put("hasExtractedLicensingInfos", (JSONArray) parser.parse(objectMapper.writeValueAsString(sw360SPDXDocument.getOtherLicensingInformationDetecteds()))); + + PrintWriter pw = new PrintWriter(releaseId + ".json"); + pw.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(SPDXJson)); + pw.flush(); + pw.close(); + } catch (ParseException | JsonProcessingException | FileNotFoundException e) { + log.error("Can not convert SW360 SPDX Document to Json"); + e.printStackTrace(); + return false; + } + + return true; + } + + private SPDXDocument getSpdxDocumentFromRelease(String releaseId) throws SW360Exception { + SPDXDocument spdxDoc; + spdxDoc = null; + final Release release = sink.getRelease(releaseId); + if (release.isSetSpdxId()) { + spdxDoc = sink.getSPDXDocument(release.getSpdxId()); + } + return spdxDoc; + } + + private DocumentCreationInformation getDocCreationInfoFromSpdxDocument(String spdxDocId) throws SW360Exception { + DocumentCreationInformation info = null; + final SPDXDocument spdxDoc = sink.getSPDXDocument(spdxDocId); + if (spdxDoc.isSetSpdxDocumentCreationInfoId()) { + info = sink.getDocumentCreationInfo(spdxDoc.getSpdxDocumentCreationInfoId()); + } + return info; + } + + private Set getPackagesInformationFromSpdxDocument(String spdxDocId) throws SW360Exception { + Set infos = new HashSet<>(); + final SPDXDocument spdxDoc = sink.getSPDXDocument(spdxDocId); + for (String packageId : spdxDoc.getSpdxPackageInfoIds()) { + PackageInformation info = sink.getPackageInfo(packageId); + infos.add(info); + } + return infos; + } + +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporterSink.java b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporterSink.java new file mode 100644 index 0000000000..51f5320cff --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporterSink.java @@ -0,0 +1,66 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdx; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import org.eclipse.sw360.datahandler.db.ComponentDatabaseHandler; +import org.eclipse.sw360.datahandler.db.ProjectDatabaseHandler; +import org.eclipse.sw360.datahandler.thrift.*; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; + +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo.SpdxDocumentCreationInfoDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.packageinfo.SpdxPackageInfoDatabaseHandler; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.sw360.datahandler.thrift.components.Release; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import java.net.MalformedURLException; + +public class SpdxBOMExporterSink { + private static final Logger log = LogManager.getLogger(SpdxBOMExporterSink.class); + + private final ProjectDatabaseHandler projectDatabaseHandler; + private final ComponentDatabaseHandler componentDatabaseHandler; + private final SpdxDocumentDatabaseHandler spdxDocumentDatabaseHandler; + private final SpdxDocumentCreationInfoDatabaseHandler creationInfoDatabaseHandler; + private final SpdxPackageInfoDatabaseHandler packageInfoDatabaseHandler; + private final User user; + + public SpdxBOMExporterSink(User user, ProjectDatabaseHandler projectDatabaseHandler, ComponentDatabaseHandler componentDatabaseHandler) throws MalformedURLException { + this.projectDatabaseHandler = projectDatabaseHandler; + this.componentDatabaseHandler = componentDatabaseHandler; + this.spdxDocumentDatabaseHandler = new SpdxDocumentDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + this.creationInfoDatabaseHandler = new SpdxDocumentCreationInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + this.packageInfoDatabaseHandler = new SpdxPackageInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + this.user = user; + } + + public SPDXDocument getSPDXDocument(String id) throws SW360Exception { + return spdxDocumentDatabaseHandler.getSPDXDocumentById(id, user); + } + + public Release getRelease(String id) throws SW360Exception { + return componentDatabaseHandler.getRelease(id, user); + } + + public DocumentCreationInformation getDocumentCreationInfo(String id) throws SW360Exception { + return creationInfoDatabaseHandler.getDocumentCreationInformationById(id, user); + } + + public PackageInformation getPackageInfo(String id) throws SW360Exception { + return packageInfoDatabaseHandler.getPackageInformationById(id, user); + } +} diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporter.java b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporter.java index d8695e3450..ad00b43b80 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporter.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporter.java @@ -1,5 +1,7 @@ /* * Copyright Siemens AG, 2019. Part of the SW360 Portal Project. + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -14,20 +16,36 @@ import org.eclipse.sw360.datahandler.thrift.attachments.Attachment; import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentContent; import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentType; +import org.eclipse.sw360.datahandler.thrift.attachments.CheckStatus; import org.eclipse.sw360.datahandler.thrift.components.Component; import org.eclipse.sw360.datahandler.thrift.components.Release; import org.eclipse.sw360.datahandler.thrift.projects.Project; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.*; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.fileinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.*; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.*; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; import org.spdx.rdfparser.InvalidSPDXAnalysisException; import org.spdx.rdfparser.SPDXDocumentFactory; import org.spdx.rdfparser.model.*; +import org.spdx.rdfparser.model.pointer.*; +import org.spdx.rdfparser.license.ExtractedLicenseInfo; +import org.spdx.rdfparser.SpdxPackageVerificationCode; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.commons.lang3.ArrayUtils; import java.io.InputStream; +import java.net.MalformedURLException; import java.util.*; import java.util.stream.Collectors; +import static org.eclipse.sw360.datahandler.common.CommonUtils.isNotNullEmptyOrWhitespace; + public class SpdxBOMImporter { private static final Logger log = LogManager.getLogger(SpdxBOMImporter.class); private final SpdxBOMImporterSink sink; @@ -36,9 +54,41 @@ public SpdxBOMImporter(SpdxBOMImporterSink sink) { this.sink = sink; } - public RequestSummary importSpdxBOMAsRelease(InputStream inputStream, AttachmentContent attachmentContent) + public ImportBomRequestPreparation prepareImportSpdxBOMAsRelease(InputStream inputStream, AttachmentContent attachmentContent) throws InvalidSPDXAnalysisException, SW360Exception { - return importSpdxBOM(inputStream, attachmentContent, SW360Constants.TYPE_RELEASE); + final ImportBomRequestPreparation requestPreparation = new ImportBomRequestPreparation(); + final SpdxDocument spdxDocument = openAsSpdx(inputStream); + final List describedPackages = Arrays.stream(spdxDocument.getDocumentDescribes()) + .filter(item -> item instanceof SpdxPackage) + .collect(Collectors.toList()); + + if (describedPackages.size() == 0) { + requestPreparation.setMessage("The provided BOM did not contain any top level packages."); + requestPreparation.setRequestStatus(RequestStatus.FAILURE); + return requestPreparation; + } else if (describedPackages.size() > 1) { + requestPreparation.setMessage("The provided BOM file contained multiple described top level packages. This is not allowed here."); + requestPreparation.setRequestStatus(RequestStatus.FAILURE); + return requestPreparation; + } + + final SpdxItem spdxItem = describedPackages.get(0); + if (spdxItem instanceof SpdxPackage) { + final SpdxPackage spdxPackage = (SpdxPackage) spdxItem; + + requestPreparation.setName(spdxPackage.getName()); + requestPreparation.setVersion(spdxPackage.getVersionInfo()); + requestPreparation.setRequestStatus(RequestStatus.SUCCESS); + } else { + requestPreparation.setMessage("Failed to get spdx package from the provided BOM file."); + requestPreparation.setRequestStatus(RequestStatus.FAILURE); + } + return requestPreparation; + } + + public RequestSummary importSpdxBOMAsRelease(InputStream inputStream, AttachmentContent attachmentContent, String newReleaseVersion, String releaseId) + throws SW360Exception { + return importSpdxBOM(inputStream, attachmentContent, SW360Constants.TYPE_RELEASE, newReleaseVersion, releaseId); } public RequestSummary importSpdxBOMAsProject(InputStream inputStream, AttachmentContent attachmentContent) @@ -48,11 +98,22 @@ public RequestSummary importSpdxBOMAsProject(InputStream inputStream, Attachment private RequestSummary importSpdxBOM(InputStream inputStream, AttachmentContent attachmentContent, String type) throws InvalidSPDXAnalysisException, SW360Exception { + return importSpdxBOM(inputStream, attachmentContent, type, null, null); + } + + private RequestSummary importSpdxBOM(InputStream inputStream, AttachmentContent attachmentContent, String type, String newReleaseVersion, String releaseId) + throws SW360Exception { final RequestSummary requestSummary = new RequestSummary(); - final SpdxDocument spdxDocument = openAsSpdx(inputStream); - final List describedPackages = Arrays.stream(spdxDocument.getDocumentDescribes()) - .filter(item -> item instanceof SpdxPackage) - .collect(Collectors.toList()); + SpdxDocument spdxDocument = null; + List describedPackages = new ArrayList<>(); + try { + spdxDocument = openAsSpdx(inputStream); + describedPackages = Arrays.stream(spdxDocument.getDocumentDescribes()) + .filter(item -> item instanceof SpdxPackage) + .collect(Collectors.toList()); + } catch (InvalidSPDXAnalysisException e) { + log.error("Can not open file to SpdxDocument " +e); + } if (describedPackages.size() == 0) { requestSummary.setTotalAffectedElements(0); @@ -73,7 +134,7 @@ private RequestSummary importSpdxBOM(InputStream inputStream, AttachmentContent if (SW360Constants.TYPE_PROJECT.equals(type)) { response = importAsProject(spdxItem, attachmentContent); } else if (SW360Constants.TYPE_RELEASE.equals(type)) { - response = importAsRelease(spdxItem, attachmentContent); + response = importAsRelease(spdxItem, attachmentContent, spdxDocument, newReleaseVersion, releaseId); } else { throw new SW360Exception("Unsupported type=[" + type + "], can not import BOM"); } @@ -121,29 +182,497 @@ private Release createReleaseFromSpdxPackage(SpdxPackage spdxPackage) { return release; } + private SPDXDocument createSPDXDocumentFromSpdxDocument(String releaseId, SpdxDocument spdxDocument) throws SW360Exception, MalformedURLException { + final SPDXDocument doc = getSpdxDocumentFromRelease(releaseId); + doc.setReleaseId(releaseId); + try { + final SpdxSnippet[] spdxSnippets = spdxDocument.getDocumentContainer().findAllSnippets().toArray(new SpdxSnippet[0]); + final Relationship[] spdxRelationships = spdxDocument.getRelationships(); + final Annotation[] spdxAnnotations = spdxDocument.getAnnotations(); + final ExtractedLicenseInfo[] extractedLicenseInfos = spdxDocument.getExtractedLicenseInfos(); + + final Set snippetInfos = createSnippetsFromSpdxSnippets(spdxSnippets); + final Set relationships = createRelationshipsFromSpdxRelationships(spdxRelationships, spdxDocument.getId()); + final Set annotations = createAnnotationsFromSpdxAnnotations(spdxAnnotations); + final Set otherLicenses = createOtherLicensesFromSpdxExtractedLicenses(extractedLicenseInfos); + + doc.setSnippets(snippetInfos) + .setRelationships(relationships) + .setAnnotations(annotations) + .setOtherLicensingInformationDetecteds(otherLicenses); + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return doc; + } + + private Set createAnnotationsFromSpdxAnnotations(Annotation[] spdxAnnotations) { + Set annotations = new HashSet(); + int index = 0; + + for(Annotation spdxAnn : spdxAnnotations) { + String annotator = spdxAnn.getAnnotator(); + String date = spdxAnn.getAnnotationDate(); + String type = spdxAnn.getAnnotationTypeTag(); + String comment = spdxAnn.getComment(); + + Annotations ann = new Annotations(); + ann.setAnnotator(verifyOrSetDefault(annotator)) + .setAnnotationDate(verifyOrSetDefault(date)) + .setAnnotationType(verifyOrSetDefault(type)) + .setAnnotationComment(verifyOrSetDefault(comment)) + .setIndex(index); + + annotations.add(ann); + index++; + } + + return annotations; + } + + private Set createSnippetsFromSpdxSnippets(SpdxSnippet[] spdxSnippets) { + Set snippets = new HashSet(); + int index = 0; + + try { + for (SpdxSnippet spdxSnippet : spdxSnippets) { + String id = spdxSnippet.getId(); + String snippetFromFile = spdxSnippet.getSnippetFromFile().getId(); + Set ranges = createSnippetRangesFromSpdxSnippet(spdxSnippet); + String licenseConcluded = spdxSnippet.getLicenseConcluded().toString(); + Set licenseInfoInFile = Arrays.stream(spdxSnippet.getLicenseInfoFromFiles()) + .map(license -> verifyOrSetDefault(license.toString())) + .collect(Collectors.toSet()); + String licenseComment = spdxSnippet.getLicenseComment(); + String copyrightText = spdxSnippet.getCopyrightText(); + String comment = spdxSnippet.getComment(); + String name = spdxSnippet.getName(); + String attributionText = String.join("|", spdxSnippet.getAttributionText()); + + SnippetInformation snippet = new SnippetInformation(); + snippet.setSPDXID(verifyOrSetDefault(id)) + .setSnippetFromFile(verifyOrSetDefault(snippetFromFile)) + .setSnippetRanges(ranges) + .setLicenseConcluded(verifyOrSetDefault(licenseConcluded)) + .setLicenseInfoInSnippets(licenseInfoInFile) + .setLicenseComments(verifyOrSetDefault(licenseComment)) + .setCopyrightText(verifyOrSetDefault(copyrightText)) + .setComment(verifyOrSetDefault(comment)) + .setName(verifyOrSetDefault(name)) + .setSnippetAttributionText(verifyOrSetDefault(attributionText)) + .setIndex(index); + + snippets.add(snippet); + index++; + } + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return snippets; + } + + private Set createSnippetRangesFromSpdxSnippet(SpdxSnippet spdxSnippet) throws InvalidSPDXAnalysisException { + StartEndPointer spdxByteRange = spdxSnippet.getByteRange(); + String[] byteRanges = rangeToStrs(spdxByteRange); + SnippetRange snippetByteRange = new SnippetRange(); + snippetByteRange.setRangeType("BYTE") + .setStartPointer(byteRanges[0]) + .setEndPointer(byteRanges[1]) + .setReference(spdxByteRange.getStartPointer().getReference().getId()) + .setIndex(0); + + StartEndPointer spdxLineRange = spdxSnippet.getLineRange(); + String[] lineRanges = rangeToStrs(spdxLineRange); + SnippetRange snippetLineRange = new SnippetRange(); + snippetLineRange.setRangeType("LINE") + .setStartPointer(lineRanges[0]) + .setEndPointer(lineRanges[1]) + .setReference(spdxLineRange.getStartPointer().getReference().getId()) + .setIndex(1); + + return new HashSet(Arrays.asList(snippetByteRange, snippetLineRange)); + } + + // refer to rangeToStr function of spdx-tools + private String[] rangeToStrs(StartEndPointer rangePointer) throws InvalidSPDXAnalysisException { + SinglePointer startPointer = rangePointer.getStartPointer(); + if (startPointer == null) { + throw new InvalidSPDXAnalysisException("Missing start pointer"); + } + SinglePointer endPointer = rangePointer.getEndPointer(); + if (endPointer == null) { + throw new InvalidSPDXAnalysisException("Missing end pointer"); + } + String start = null; + if (startPointer instanceof ByteOffsetPointer) { + start = String.valueOf(((ByteOffsetPointer)startPointer).getOffset()); + } else if (startPointer instanceof LineCharPointer) { + start = String.valueOf(((LineCharPointer)startPointer).getLineNumber()); + } else { + log.error("Unknown pointer type for start pointer "+startPointer.toString()); + throw new InvalidSPDXAnalysisException("Unknown pointer type for start pointer"); + } + String end = null; + if (endPointer instanceof ByteOffsetPointer) { + end = String.valueOf(((ByteOffsetPointer)endPointer).getOffset()); + } else if (endPointer instanceof LineCharPointer) { + end = String.valueOf(((LineCharPointer)endPointer).getLineNumber()); + } else { + log.error("Unknown pointer type for start pointer "+startPointer.toString()); + throw new InvalidSPDXAnalysisException("Unknown pointer type for start pointer"); + } + return new String[] { start, end }; + } + + private Set createRelationshipsFromSpdxRelationships(Relationship[] spdxRelationships, String spdxElementId) { + Set relationships = new HashSet(); + int index = 0; + + for (Relationship spdxRelationship : spdxRelationships) { + if (!(spdxRelationship.getRelatedSpdxElement() instanceof SpdxFile)) { + String type = spdxRelationship.getRelationshipType().toTag(); + String relatedSpdxElement = spdxRelationship.getRelatedSpdxElement().getId(); + String comment = spdxRelationship.getComment(); + + RelationshipsBetweenSPDXElements relationship = new RelationshipsBetweenSPDXElements(); + relationship.setSpdxElementId(verifyOrSetDefault(spdxElementId)) + .setRelationshipType(verifyOrSetDefault(type)) + .setRelatedSpdxElement(verifyOrSetDefault(relatedSpdxElement)) + .setRelationshipComment(verifyOrSetDefault(comment)) + .setIndex(index); + + relationships.add(relationship); + index++; + } + } + + return relationships; + } + + private Set createOtherLicensesFromSpdxExtractedLicenses(ExtractedLicenseInfo[] spdxExtractedLicenses) { + Set otherLicenses = new HashSet(); + int index = 0; + + for (ExtractedLicenseInfo spdxExtractedLicense : spdxExtractedLicenses) { + String licenseId = spdxExtractedLicense.getLicenseId(); + String extractedText = spdxExtractedLicense.getExtractedText(); + String name = spdxExtractedLicense.getName(); + Set crossRef = new HashSet(Arrays.asList(verifyOrSetDefault(spdxExtractedLicense.getCrossRef()))); + String comment = spdxExtractedLicense.getComment(); + + OtherLicensingInformationDetected otherLicense = new OtherLicensingInformationDetected(); + otherLicense.setLicenseId(verifyOrSetDefault(licenseId)) + .setExtractedText(verifyOrSetDefault(extractedText)) + .setLicenseName(verifyOrSetDefault(name)) + .setLicenseCrossRefs(crossRef) + .setLicenseComment(verifyOrSetDefault(comment)) + .setIndex(index); + + otherLicenses.add(otherLicense); + index++; + } + + return otherLicenses; + } + + private DocumentCreationInformation createDocumentCreationInfoFromSpdxDocument(String spdxDocId, SpdxDocument spdxDocument) throws SW360Exception, MalformedURLException { + final DocumentCreationInformation info = getDocCreationInfoFromSpdxDocument(spdxDocId); + info.setSpdxDocumentId(spdxDocId); + + try { + final String spdxVersion = spdxDocument.getSpecVersion(); + final String dataLicense = spdxDocument.getDataLicense().toString(); + final String spdxId = spdxDocument.getId(); + final String name = spdxDocument.getName(); + final String documentNamespace = spdxDocument.getDocumentContainer().getDocumentNamespace(); + final Set refs = createExternalDocumentRefsFromSpdxDocument(spdxDocument); + final String licenseListVersion = spdxDocument.getCreationInfo().getLicenseListVersion(); + final Set creators = createCreatorFromSpdxDocument(spdxDocument); + final String createdDate = spdxDocument.getCreationInfo().getCreated(); + final String creatorComment = spdxDocument.getCreationInfo().getComment(); + final String documentComment = spdxDocument.getDocumentComment(); + + info.setSpdxVersion(verifyOrSetDefault(spdxVersion)) + .setDataLicense(verifyOrSetDefault(dataLicense)) + .setSPDXID(verifyOrSetDefault(spdxId)) + .setName(verifyOrSetDefault(name)) + .setDocumentNamespace(verifyOrSetDefault(documentNamespace)) + .setExternalDocumentRefs(refs) + .setLicenseListVersion(verifyOrSetDefault(licenseListVersion)) + .setCreator(creators) + .setCreated(verifyOrSetDefault(createdDate)) + .setCreatorComment(verifyOrSetDefault(creatorComment)) + .setDocumentComment(verifyOrSetDefault(documentComment)); + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return info; + } + + private Set createExternalDocumentRefsFromSpdxDocument(SpdxDocument spdxDocument) { + Set refs = new HashSet(); + int index = 0; + + try { + ExternalDocumentRef[] externalDocumentRefs = spdxDocument.getDocumentContainer().getExternalDocumentRefs(); + + for (ExternalDocumentRef externalDocumentRef : externalDocumentRefs) { + Checksum spdxChecksum = externalDocumentRef.getChecksum(); + + String externalDocumentId = externalDocumentRef.getExternalDocumentId(); + String spdxDocumentNamespace = externalDocumentRef.getSpdxDocumentNamespace(); + CheckSum checksum = new CheckSum(); + checksum.setAlgorithm(org.spdx.rdfparser.model.Checksum.CHECKSUM_ALGORITHM_TO_TAG.get(spdxChecksum.getAlgorithm()).replace(":", "")) + .setChecksumValue(spdxChecksum.getValue()); + + ExternalDocumentReferences ref = new ExternalDocumentReferences(); + ref.setExternalDocumentId(verifyOrSetDefault(externalDocumentId)) + .setChecksum(checksum) + .setSpdxDocument(verifyOrSetDefault(spdxDocumentNamespace)) + .setIndex(index); + + refs.add(ref); + index++; + } + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return refs; + } + + private Set createCreatorFromSpdxDocument(SpdxDocument spdxDocument) { + Set creators = new HashSet(); + int index = 0; + + try { + String[] spdxCreators = spdxDocument.getCreationInfo().getCreators(); + + for (String spdxCreator : spdxCreators) { + String[] data = spdxCreator.split(":"); + if (data.length < 2) { + log.error("Failed to get SPDX creator from " + spdxCreator + "!"); + continue; + } + String type = data[0].trim(); + String value = spdxCreator.substring(data[0].length()+1).trim(); + + Creator creator = new Creator(); + creator.setType(verifyOrSetDefault(type)); + creator.setValue(verifyOrSetDefault(value)); + creator.setIndex(index); + + creators.add(creator); + index++; + } + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return creators; + } + + private PackageInformation createPackageInfoFromSpdxPackage(String spdxDocId, SpdxPackage spdxPackage) throws SW360Exception, MalformedURLException { + PackageVerificationCode PVC = new PackageVerificationCode(); + try { + PVC = createPVCFromSpdxPackage(spdxPackage); + } catch (NullPointerException e) { + PVC.setExcludedFiles(Collections.emptySet()) + .setValue(verifyOrSetDefault("")); + log.error("Can not get PVC " + e); + } + + Set checksums = new HashSet<>(); + try { + checksums = createCheckSumsFromSpdxChecksums(spdxPackage); + } catch (NullPointerException e) { + Collections.emptySet(); + log.error("Can not get checksums " + e); + } + + String licenseDeclared = ""; + try { + licenseDeclared = createLicenseDeclaredFromSpdxLicenseDeclared(spdxPackage); + } catch (NullPointerException e) { + log.error("Can not get licenseDeclared " + e); + } + + Set externalRefs = new HashSet<>(); + try { + externalRefs = createExternalReferenceFromSpdxPackage(spdxPackage); + } catch (NullPointerException e) { + log.error("Can not get externalRefs " + e); + externalRefs = Collections.emptySet(); + } + + PackageInformation pInfo = getPackageInformationFromSpdxDocument(spdxDocId, spdxPackage.getName()); + pInfo.setSpdxDocumentId(spdxDocId); + + try { + final String name = spdxPackage.getName(); + final String spdxId = spdxPackage.getId(); + final String versionInfo = spdxPackage.getVersionInfo(); + final String packageFileName = spdxPackage.getPackageFileName(); + final String supplier = spdxPackage.getSupplier(); + final String originator = spdxPackage.getOriginator(); + final String downloadLocation = spdxPackage.getDownloadLocation(); + final boolean fileAnalyzed = spdxPackage.isFilesAnalyzed(); + final String homepage = spdxPackage.getHomepage(); + final String sourceInfo = spdxPackage.getSourceInfo(); + final String licenseConcluded = spdxPackage.getLicenseConcluded().toString(); + final Set licenseInfosFromFiles = Arrays.stream(spdxPackage.getLicenseInfoFromFiles()) + .map(license -> license.toString()) + .collect(Collectors.toSet()); + final String licenseComment = spdxPackage.getLicenseComment(); + final String copyrightText = spdxPackage.getCopyrightText(); + final String summary = spdxPackage.getSummary(); + final String description = spdxPackage.getDescription(); + final String comment = spdxPackage.getComment(); + final Set attributionText = new HashSet(Arrays.asList(verifyOrSetDefault(spdxPackage.getAttributionText()))); + final Set annotations = createAnnotationsFromSpdxAnnotations(spdxPackage.getAnnotations()); + + pInfo.setName(verifyOrSetDefault(name)) + .setSPDXID(verifyOrSetDefault(spdxId)) + .setVersionInfo(verifyOrSetDefault(versionInfo)) + .setPackageFileName(verifyOrSetDefault(packageFileName)) + .setSupplier(verifyOrSetDefault(supplier)) + .setOriginator(verifyOrSetDefault(originator)) + .setDownloadLocation(verifyOrSetDefault(downloadLocation)) + .setFilesAnalyzed(fileAnalyzed) + .setPackageVerificationCode(PVC) + .setChecksums(checksums) + .setHomepage(verifyOrSetDefault(homepage)) + .setSourceInfo(verifyOrSetDefault(sourceInfo)) + .setLicenseConcluded(verifyOrSetDefault(licenseConcluded)) + .setLicenseInfoFromFiles(licenseInfosFromFiles) + .setLicenseDeclared(verifyOrSetDefault(licenseDeclared)) + .setLicenseComments(verifyOrSetDefault(licenseComment)) + .setCopyrightText(verifyOrSetDefault(copyrightText)) + .setSummary(verifyOrSetDefault(summary)) + .setDescription(verifyOrSetDefault(description)) + .setPackageComment(verifyOrSetDefault(comment)) + .setExternalRefs(externalRefs) + .setAttributionText(attributionText) + .setAnnotations(annotations); + } catch (InvalidSPDXAnalysisException e) { + log.error("createPackageInfoFromSpdxPackage error " + e); + } + + return pInfo; + } + + private PackageVerificationCode createPVCFromSpdxPackage(SpdxPackage spdxPackage) { + try { + PackageVerificationCode PVC = new PackageVerificationCode(); + SpdxPackageVerificationCode spdxPVC = spdxPackage.getPackageVerificationCode(); + Set excludedFileNames = new HashSet(Arrays.asList(verifyOrSetDefault(spdxPVC.getExcludedFileNames()))); + String value = spdxPVC.getValue(); + + PVC.setExcludedFiles(excludedFileNames) + .setValue(verifyOrSetDefault(value)); + return PVC; + } catch (InvalidSPDXAnalysisException e) { + log.error("Error get PVC " + e); + return null; + } + } + + private Set createExternalReferenceFromSpdxPackage(SpdxPackage spdxPackage) { + Set refs = new HashSet(); + int index = 0; + + try { + ExternalRef[] spdxExternalRefs = spdxPackage.getExternalRefs(); + for (ExternalRef spdxRef : spdxExternalRefs) { + String category = spdxRef.getReferenceCategory().getTag(); + String locator = spdxRef.getReferenceLocator(); + String type = spdxRef.getReferenceType().toString(); + String comment = spdxRef.getComment(); + + ExternalReference ref = new ExternalReference(); + ref.setReferenceCategory(verifyOrSetDefault(category)) + .setReferenceLocator(verifyOrSetDefault(locator)) + .setReferenceType(verifyOrSetDefault(type)) + .setComment(verifyOrSetDefault(comment)) + .setIndex(index); + + refs.add(ref); + index++; + } + } catch (InvalidSPDXAnalysisException e) { + log.error(e); + } + + return refs; + } + + private Set createCheckSumsFromSpdxChecksums(SpdxPackage spdxPackage) { + Set checksums = new HashSet(); + int index = 0; + try { + Checksum[] spdxChecksums = spdxPackage.getChecksums(); + for (Checksum spdxChecksum : spdxChecksums) { + String algorithm = org.spdx.rdfparser.model.Checksum.CHECKSUM_ALGORITHM_TO_TAG.get(spdxChecksum.getAlgorithm()).replace(":", ""); + String value = spdxChecksum.getValue(); + CheckSum checksum = new CheckSum(); + checksum.setAlgorithm(verifyOrSetDefault(algorithm)) + .setChecksumValue(verifyOrSetDefault(value)) + .setIndex(index); + checksums.add(checksum); + index++; + } + } catch (InvalidSPDXAnalysisException e) { + checksums = Collections.emptySet(); + } + return checksums; + } + + private String createLicenseDeclaredFromSpdxLicenseDeclared(SpdxPackage spdxPackage) { + try { + return spdxPackage.getLicenseDeclared().toString(); + } catch (InvalidSPDXAnalysisException e) { + log.error("Can not get licenseDeclared " + e); + } + return null; + } + private Attachment makeAttachmentFromContent(AttachmentContent attachmentContent) { Attachment attachment = new Attachment(); attachment.setAttachmentContentId(attachmentContent.getId()); - attachment.setAttachmentType(AttachmentType.OTHER); + attachment.setAttachmentType(AttachmentType.SBOM); attachment.setCreatedComment("Used for SPDX Bom import"); attachment.setFilename(attachmentContent.getFilename()); + attachment.setCheckStatus(CheckStatus.NOTCHECKED); return attachment; } private Optional importAsRelease(SpdxElement relatedSpdxElement) throws SW360Exception { - return importAsRelease(relatedSpdxElement, null); + return importAsRelease(relatedSpdxElement, null, null, null, null); } - private Optional importAsRelease(SpdxElement relatedSpdxElement, AttachmentContent attachmentContent) throws SW360Exception { + private Optional importAsRelease(SpdxElement relatedSpdxElement, AttachmentContent attachmentContent, + SpdxDocument spdxDocument, String newReleaseVersion, String releaseId) throws SW360Exception { if (relatedSpdxElement instanceof SpdxPackage) { final SpdxPackage spdxPackage = (SpdxPackage) relatedSpdxElement; - SpdxBOMImporterSink.Response component = importAsComponent(spdxPackage); - final String componentId = component.getId(); - - final Release release = createReleaseFromSpdxPackage(spdxPackage); - release.setComponentId(componentId); + final Release release; + SpdxBOMImporterSink.Response component; + if (isNotNullEmptyOrWhitespace(releaseId)) { + release = sink.getRelease(releaseId); + component = new SpdxBOMImporterSink.Response(release.getComponentId(), true); + } else { + component = importAsComponent(spdxPackage); + final String componentId = component.getId(); + + release = createReleaseFromSpdxPackage(spdxPackage); + if (isNotNullEmptyOrWhitespace(newReleaseVersion)) + release.setVersion(newReleaseVersion); + release.setComponentId(componentId); + } final Relationship[] relationships = spdxPackage.getRelationships(); List releases = importAsReleases(relationships); @@ -157,6 +686,13 @@ private Optional importAsRelease(SpdxElement relat final SpdxBOMImporterSink.Response response = sink.addRelease(release); + + try { + importSpdxDocument(response.getId(), spdxDocument, spdxPackage); + } catch (MalformedURLException e) { + log.error(e); + } + response.addChild(component); return Optional.of(response); } else { @@ -165,6 +701,83 @@ private Optional importAsRelease(SpdxElement relat } } + private void importSpdxDocument(String releaseId, SpdxDocument spdxDocument, SpdxPackage spdxPackage) throws SW360Exception, MalformedURLException { + final SPDXDocument spdxDoc = createSPDXDocumentFromSpdxDocument(releaseId, spdxDocument); + final SpdxBOMImporterSink.Response spdxDocRes = sink.addOrUpdateSpdxDocument(spdxDoc); + final String spdxDocId = spdxDocRes.getId(); + + final DocumentCreationInformation docCreationInfo = createDocumentCreationInfoFromSpdxDocument(spdxDocId, spdxDocument); + final SpdxBOMImporterSink.Response docCreationInfoRes = sink.addOrUpdateDocumentCreationInformation(docCreationInfo); + final String docCreationInfoId = docCreationInfoRes.getId(); + + List packages = new ArrayList<>(); + try { + packages = spdxDocument.getDocumentContainer().findAllPackages(); + } catch (InvalidSPDXAnalysisException e) { + log.error("Can not get list package from SpdxDocument"); + e.printStackTrace(); + packages = Collections.emptyList(); + } + + int index = 1; + for (SpdxPackage packageElement : packages) { + log.info("Import package: " + packageElement.toString()); + PackageInformation packageInfo = createPackageInfoFromSpdxPackage(spdxDocId, packageElement); + if (ArrayUtils.isNotEmpty(packageElement.getRelationships())) { + Set packageReleaseRelationship = createRelationshipsFromSpdxRelationships(packageElement.getRelationships(), packageElement.getId()); + packageInfo.setRelationships(packageReleaseRelationship); + } else { + packageInfo.setRelationships(Collections.emptySet()); + } + + if (packageElement.getName().equals(spdxPackage.getName())) { + packageInfo.setIndex(0); + } else { + packageInfo.setIndex(index); + index ++; + } + SpdxBOMImporterSink.Response packageInfoRes = sink.addOrUpdatePackageInformation(packageInfo); + } + } + + private SPDXDocument getSpdxDocumentFromRelease(String releaseId) throws SW360Exception, MalformedURLException { + SPDXDocument spdxDoc; + final Release release = sink.getRelease(releaseId); + if (release.isSetSpdxId()) { + spdxDoc = sink.getSPDXDocument(release.getSpdxId()); + } else { + spdxDoc = new SPDXDocument(); + } + return spdxDoc; + } + + private DocumentCreationInformation getDocCreationInfoFromSpdxDocument(String spdxDocId) throws SW360Exception, MalformedURLException { + DocumentCreationInformation info; + final SPDXDocument spdxDoc = sink.getSPDXDocument(spdxDocId); + if (spdxDoc.isSetSpdxDocumentCreationInfoId()) { + info = sink.getDocumentCreationInfo(spdxDoc.getSpdxDocumentCreationInfoId()); + } else { + info = new DocumentCreationInformation(); + } + return info; + } + + private PackageInformation getPackageInformationFromSpdxDocument(String spdxDocId, String packageName) throws SW360Exception, MalformedURLException { + PackageInformation info; + final SPDXDocument spdxDoc = sink.getSPDXDocument(spdxDocId); + if (spdxDoc.getSpdxPackageInfoIdsSize() > 0) { + for (String packageId : spdxDoc.getSpdxPackageInfoIds()) { + if (sink.getPackageInfo(packageId).getName().equals(packageName)) { + info = sink.getPackageInfo(packageId); + return info; + } + } + return new PackageInformation(); + } else { + return new PackageInformation(); + } + } + private Map makeReleaseIdToRelationship(List releases) { return releases.stream() .collect(Collectors.toMap(SpdxBOMImporterSink.Response::getId, SpdxBOMImporterSink.Response::getReleaseRelationship)); @@ -237,4 +850,147 @@ private Optional importAsProject(SpdxElement spdxE return Optional.empty(); } } + + + private String verifyOrSetDefault(String value) { + return (isNotNullEmptyOrWhitespace(value)) ? value : ""; + } + + private String[] verifyOrSetDefault(String[] values) { + return (values != null && values.length > 0) ? values : new String[0]; + } + + + public RequestSummary importSpdxBOMAsReleaseForTest(InputStream inputStream, AttachmentContent attachmentContent) + throws InvalidSPDXAnalysisException, SW360Exception { + return importSpdxBOMForTest(inputStream, attachmentContent, SW360Constants.TYPE_RELEASE); + } + + public RequestSummary importSpdxBOMAsProjectForTest(InputStream inputStream, AttachmentContent attachmentContent) + throws InvalidSPDXAnalysisException, SW360Exception { + return importSpdxBOMForTest(inputStream, attachmentContent, SW360Constants.TYPE_PROJECT); + } + private RequestSummary importSpdxBOMForTest(InputStream inputStream, AttachmentContent attachmentContent, String type) + throws InvalidSPDXAnalysisException, SW360Exception { + final RequestSummary requestSummary = new RequestSummary(); + final SpdxDocument spdxDocument = openAsSpdx(inputStream); + final List describedPackages = Arrays.stream(spdxDocument.getDocumentDescribes()) + .filter(item -> item instanceof SpdxPackage) + .collect(Collectors.toList()); + + if (describedPackages.size() == 0) { + requestSummary.setTotalAffectedElements(0); + requestSummary.setTotalElements(0); + requestSummary.setMessage("The provided BOM did not contain any top level packages."); + requestSummary.setRequestStatus(RequestStatus.FAILURE); + return requestSummary; + } else if (describedPackages.size() > 1) { + requestSummary.setTotalAffectedElements(0); + requestSummary.setTotalElements(0); + requestSummary.setMessage("The provided BOM file contained multiple described top level packages. This is not allowed here."); + requestSummary.setRequestStatus(RequestStatus.FAILURE); + return requestSummary; + } + + final SpdxItem spdxItem = describedPackages.get(0); + final Optional response; + if (SW360Constants.TYPE_PROJECT.equals(type)) { + response = importAsProjectForTest(spdxItem, attachmentContent); + } else if (SW360Constants.TYPE_RELEASE.equals(type)) { + response = importAsReleaseForTest(spdxItem, attachmentContent); + } else { + throw new SW360Exception("Unsupported type=[" + type + "], can not import BOM"); + } + + if (response.isPresent()) { + requestSummary.setRequestStatus(RequestStatus.SUCCESS); + requestSummary.setTotalAffectedElements(response.get().countAffected()); + requestSummary.setTotalElements(response.get().count()); + requestSummary.setMessage(response.get().getId()); + } else { + requestSummary.setRequestStatus(RequestStatus.FAILURE); + requestSummary.setTotalAffectedElements(-1); + requestSummary.setTotalElements(-1); + requestSummary.setMessage("Failed to import the BOM as type=[" + type + "]."); + } + return requestSummary; + } + private Optional importAsReleaseForTest(SpdxElement relatedSpdxElement) throws SW360Exception { + return importAsReleaseForTest(relatedSpdxElement, null); + } + private Optional importAsReleaseForTest(SpdxElement relatedSpdxElement, AttachmentContent attachmentContent) throws SW360Exception { + if (relatedSpdxElement instanceof SpdxPackage) { + final SpdxPackage spdxPackage = (SpdxPackage) relatedSpdxElement; + + SpdxBOMImporterSink.Response component = importAsComponent(spdxPackage); + final String componentId = component.getId(); + + final Release release = createReleaseFromSpdxPackage(spdxPackage); + release.setComponentId(componentId); + + final Relationship[] relationships = spdxPackage.getRelationships(); + List releases = importAsReleasesForTest(relationships); + Map releaseIdToRelationship = makeReleaseIdToRelationship(releases); + release.setReleaseIdToRelationship(releaseIdToRelationship); + + if(attachmentContent != null) { + Attachment attachment = makeAttachmentFromContent(attachmentContent); + release.setAttachments(Collections.singleton(attachment)); + } + + + final SpdxBOMImporterSink.Response response = sink.addRelease(release); + response.addChild(component); + return Optional.of(response); + } else { + log.debug("Unsupported SpdxElement: " + relatedSpdxElement.getClass().getCanonicalName()); + return Optional.empty(); + } + } + private List importAsReleasesForTest(Relationship[] relationships) throws SW360Exception { + List releases = new ArrayList<>(); + + Map typeToSupplierMap = new HashMap<>(); + typeToSupplierMap.put(Relationship.RelationshipType.CONTAINS, ReleaseRelationship.CONTAINED); + + for (Relationship relationship : relationships) { + final Relationship.RelationshipType relationshipType = relationship.getRelationshipType(); + if(! typeToSupplierMap.keySet().contains(relationshipType)) { + log.debug("Unsupported RelationshipType: " + relationshipType.toString()); + continue; + } + + final SpdxElement relatedSpdxElement = relationship.getRelatedSpdxElement(); + final Optional releaseId = importAsReleaseForTest(relatedSpdxElement); + releaseId.map(response -> { + response.setReleaseRelationship(typeToSupplierMap.get(relationshipType)); + return response; + }).ifPresent(releases::add); + } + return releases; + } + private Optional importAsProjectForTest(SpdxElement spdxElement, AttachmentContent attachmentContent) throws SW360Exception { + if (spdxElement instanceof SpdxPackage) { + final SpdxPackage spdxPackage = (SpdxPackage) spdxElement; + + final Project project = creatProjectFromSpdxPackage(spdxPackage); + + final Relationship[] relationships = spdxPackage.getRelationships(); + List releases = importAsReleasesForTest(relationships); + Map releaseIdToProjectRelationship = makeReleaseIdToProjectRelationship(releases); + project.setReleaseIdToUsage(releaseIdToProjectRelationship); + + if(attachmentContent != null) { + Attachment attachment = makeAttachmentFromContent(attachmentContent); + project.setAttachments(Collections.singleton(attachment)); + } + + final SpdxBOMImporterSink.Response response = sink.addProject(project); + response.addChilds(releases); + return Optional.of(response); + } else { + log.debug("Unsupported SpdxElement: " + spdxElement.getClass().getCanonicalName()); + return Optional.empty(); + } + } } diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporterSink.java b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporterSink.java index 8a1f07ee13..c28295d0eb 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporterSink.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMImporterSink.java @@ -9,6 +9,7 @@ */ package org.eclipse.sw360.spdx; +import org.eclipse.sw360.datahandler.common.DatabaseSettings; import org.eclipse.sw360.datahandler.common.CommonUtils; import org.eclipse.sw360.datahandler.db.ComponentDatabaseHandler; import org.eclipse.sw360.datahandler.db.ProjectDatabaseHandler; @@ -16,12 +17,21 @@ import org.eclipse.sw360.datahandler.thrift.attachments.Attachment; import org.eclipse.sw360.datahandler.thrift.components.Component; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; + +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo.SpdxDocumentCreationInfoDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.packageinfo.SpdxPackageInfoDatabaseHandler; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.sw360.datahandler.thrift.components.Release; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.users.User; +import java.net.MalformedURLException; import java.util.*; import java.util.stream.Collectors; @@ -30,11 +40,17 @@ public class SpdxBOMImporterSink { private final ProjectDatabaseHandler projectDatabaseHandler; private final ComponentDatabaseHandler componentDatabaseHandler; + private final SpdxDocumentDatabaseHandler spdxDocumentDatabaseHandler; + private final SpdxDocumentCreationInfoDatabaseHandler creationInfoDatabaseHandler; + private final SpdxPackageInfoDatabaseHandler packageInfoDatabaseHandler; private final User user; - public SpdxBOMImporterSink(User user, ProjectDatabaseHandler projectDatabaseHandler, ComponentDatabaseHandler componentDatabaseHandler) { + public SpdxBOMImporterSink(User user, ProjectDatabaseHandler projectDatabaseHandler, ComponentDatabaseHandler componentDatabaseHandler) throws MalformedURLException { this.projectDatabaseHandler = projectDatabaseHandler; this.componentDatabaseHandler = componentDatabaseHandler; + this.spdxDocumentDatabaseHandler = new SpdxDocumentDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + this.creationInfoDatabaseHandler = new SpdxDocumentCreationInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + this.packageInfoDatabaseHandler = new SpdxPackageInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); this.user = user; } @@ -68,6 +84,67 @@ public Response addRelease(Release release) throws SW360Exception { return new Response(releaseId, AddDocumentRequestStatus.SUCCESS.equals(addDocumentRequestSummary.getRequestStatus())); } + public Response addOrUpdateSpdxDocument(SPDXDocument spdxDocument) throws SW360Exception { + log.debug("create or update SPDXDocument"); + // SpdxDocumentDatabaseHandler handler = new SpdxDocumentDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + RequestStatus requestStatus; + String spdxDocId; + if (spdxDocument.isSetId()) { + requestStatus = spdxDocumentDatabaseHandler.updateSPDXDocument(spdxDocument, user); + spdxDocId = spdxDocument.getId(); + } else { + AddDocumentRequestSummary addDocumentRequestSummary = spdxDocumentDatabaseHandler.addSPDXDocument(spdxDocument, user); + requestStatus = RequestStatus.findByValue(addDocumentRequestSummary.getRequestStatus().getValue()); + spdxDocId = addDocumentRequestSummary.getId(); + } + + // final String spdxDocId = addDocumentRequestSummary.getId(); + if(spdxDocId == null || spdxDocId.isEmpty()) { + throw new SW360Exception("Id of spdx document should not be empty. " + requestStatus.toString()); + } + return new Response(spdxDocId, RequestStatus.SUCCESS.equals(requestStatus)); + } + + public Response addOrUpdateDocumentCreationInformation(DocumentCreationInformation documentCreationInfo) throws SW360Exception { + log.debug("create or update DocumentCreationInformation { name='" + documentCreationInfo.getName() + "' }"); + // SpdxDocumentCreationInfoDatabaseHandler handler = new SpdxDocumentCreationInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + RequestStatus requestStatus; + String docCreationInfoId; + if (documentCreationInfo.isSetId()) { + requestStatus = creationInfoDatabaseHandler.updateDocumentCreationInformation(documentCreationInfo, user); + docCreationInfoId = documentCreationInfo.getId(); + } else { + AddDocumentRequestSummary addDocumentRequestSummary = creationInfoDatabaseHandler.addDocumentCreationInformation(documentCreationInfo, user); + requestStatus = RequestStatus.findByValue(addDocumentRequestSummary.getRequestStatus().getValue()); + docCreationInfoId = addDocumentRequestSummary.getId(); + } + // final AddDocumentRequestSummary addDocumentRequestSummary = handler.addDocumentCreationInformation(documentCreationInfo, user); + + // final String docCreationInfoId = addDocumentRequestSummary.getId(); + if(docCreationInfoId == null || docCreationInfoId.isEmpty()) { + throw new SW360Exception("Id of added document creation information should not be empty. " + requestStatus.toString()); + } + return new Response(docCreationInfoId, RequestStatus.SUCCESS.equals(requestStatus)); + } + + public Response addOrUpdatePackageInformation(PackageInformation packageInfo) throws SW360Exception { + log.debug("create or update PackageInfomation { name='" + packageInfo.getName() + "' }"); + RequestStatus requestStatus; + String packageInfoId; + if (packageInfo.isSetId()) { + requestStatus = packageInfoDatabaseHandler.updatePackageInformation(packageInfo, user); + packageInfoId = packageInfo.getId(); + } else { + AddDocumentRequestSummary addDocumentRequestSummary = packageInfoDatabaseHandler.addPackageInformation(packageInfo, user); + requestStatus = RequestStatus.findByValue(addDocumentRequestSummary.getRequestStatus().getValue()); + packageInfoId = addDocumentRequestSummary.getId(); + } + if (packageInfoId == null || packageInfoId.isEmpty()) { + throw new SW360Exception("Id of added package information should not be empty. " + requestStatus.toString()); + } + return new Response(packageInfoId, RequestStatus.SUCCESS.equals(requestStatus)); + } + public Response addProject(Project project) throws SW360Exception { log.debug("create Project { name='" + project.getName() + "', version='" + project.getVersion() + "' }"); @@ -91,6 +168,25 @@ public Response addProject(Project project) throws SW360Exception { return new Response(projectId, AddDocumentRequestStatus.SUCCESS.equals(addDocumentRequestSummary.getRequestStatus())); } + public Release getRelease(String id) throws SW360Exception { + return componentDatabaseHandler.getRelease(id, user); + } + + public SPDXDocument getSPDXDocument(String id) throws SW360Exception { + // SpdxDocumentDatabaseHandler handler = new SpdxDocumentDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + return spdxDocumentDatabaseHandler.getSPDXDocumentById(id, user); + } + + public DocumentCreationInformation getDocumentCreationInfo(String id) throws SW360Exception { + // SpdxDocumentCreationInfoDatabaseHandler handler = new SpdxDocumentCreationInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + return creationInfoDatabaseHandler.getDocumentCreationInformationById(id, user); + } + + public PackageInformation getPackageInfo(String id) throws SW360Exception { + // SpdxPackageInfoDatabaseHandler handler = new SpdxPackageInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + return packageInfoDatabaseHandler.getPackageInformationById(id, user); + } + public static class Response { private final String id; private final List childs; diff --git a/backend/src-common/src/test/java/org/eclipse/sw360/spdx/SpdxBOMImporterTest.java b/backend/src-common/src/test/java/org/eclipse/sw360/spdx/SpdxBOMImporterTest.java index 7a26e3adea..2b82f58113 100644 --- a/backend/src-common/src/test/java/org/eclipse/sw360/spdx/SpdxBOMImporterTest.java +++ b/backend/src-common/src/test/java/org/eclipse/sw360/spdx/SpdxBOMImporterTest.java @@ -41,7 +41,6 @@ public class SpdxBOMImporterTest { @Before public void before() throws Exception { spdxBOMImporter = new SpdxBOMImporter(spdxBOMImporterSink); - inputStream = getClass() .getClassLoader().getResourceAsStream("bom.spdx.rdf"); @@ -73,7 +72,7 @@ public void after() throws Exception { @Test public void testProject() throws Exception { - final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsProject(inputStream, attachmentContent); + final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsProjectForTest(inputStream, attachmentContent); assertNotNull(requestSummary); verify(spdxBOMImporterSink, times(1)).addProject(Matchers.any()); @@ -83,7 +82,7 @@ public void testProject() throws Exception { @Test public void testRelease() throws Exception { - final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsRelease(inputStream, attachmentContent); + final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsReleaseForTest(inputStream, attachmentContent); assertNotNull(requestSummary); verify(spdxBOMImporterSink, times(4)).addComponent(Matchers.any()); diff --git a/backend/src/pom.xml b/backend/src/pom.xml index d759dec221..bef4ad19e3 100644 --- a/backend/src/pom.xml +++ b/backend/src/pom.xml @@ -42,6 +42,9 @@ src-wsimport src-changelogs src-health + src-spdxdocument + src-spdxdocumentcreationinfo + src-spdxpackageinfo diff --git a/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java b/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java index 431e3968c6..9436c44eec 100644 --- a/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java +++ b/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java @@ -619,10 +619,25 @@ public String getCyclicLinkedReleasePath(Release release, User user) throws TExc } @Override - public RequestSummary importBomFromAttachmentContent(User user, String attachmentContentId) throws TException { + public ImportBomRequestPreparation prepareImportBom(User user, String attachmentContentId) throws TException { assertNotNull(attachmentContentId); assertUser(user); - return handler.importBomFromAttachmentContent(user, attachmentContentId); + return handler.prepareImportBom(user, attachmentContentId); + } + + @Override + public RequestSummary importBomFromAttachmentContent(User user, String attachmentContentId, String newReleaseVersion, String releaseId, String rdfFilePath) throws TException { + assertNotNull(attachmentContentId); + assertUser(user); + return handler.importBomFromAttachmentContent(user, attachmentContentId, newReleaseVersion, releaseId, rdfFilePath); + } + + + @Override + public RequestSummary exportSPDX(User user, String releaseId, String outputFormat) throws TException { + assertNotNull(releaseId); + assertUser(user); + return handler.exportSPDX(user, releaseId, outputFormat); } @Override diff --git a/backend/src/src-fossology/src/main/java/org/eclipse/sw360/fossology/rest/FossologyRestClient.java b/backend/src/src-fossology/src/main/java/org/eclipse/sw360/fossology/rest/FossologyRestClient.java index cfeafd4b29..050b978720 100644 --- a/backend/src/src-fossology/src/main/java/org/eclipse/sw360/fossology/rest/FossologyRestClient.java +++ b/backend/src/src-fossology/src/main/java/org/eclipse/sw360/fossology/rest/FossologyRestClient.java @@ -219,6 +219,7 @@ public int startScanning(int uploadId) { headers.set("Authorization", "Bearer " + token); headers.set("folderId", folderId); headers.set("uploadId", uploadId + ""); + headers.set("Content-Type", "application/json"); ObjectNode analysis = objectMapper.createObjectNode(); analysis.put("bucket", true); diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/ModerationHandler.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/ModerationHandler.java index 0ba92b6f73..91e854463e 100644 --- a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/ModerationHandler.java +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/ModerationHandler.java @@ -27,6 +27,9 @@ import org.eclipse.sw360.datahandler.thrift.projects.ClearingRequest; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; import org.eclipse.sw360.moderation.db.ModerationDatabaseHandler; import java.io.IOException; @@ -125,6 +128,54 @@ public void createProjectDeleteRequest(Project project, User user) throws TExcep handler.createRequest(project, user, true); } + @Override + public RequestStatus createSPDXDocumentRequest(SPDXDocument spdx, User user) throws TException { + assertUser(user); + assertNotNull(spdx); + + return handler.createRequest(spdx, user, false); + } + + @Override + public void createSPDXDocumentDeleteRequest(SPDXDocument spdx, User user) throws TException { + assertUser(user); + assertNotNull(spdx); + + handler.createRequest(spdx, user, true); + } + + @Override + public RequestStatus createSpdxDocumentCreationInfoRequest(DocumentCreationInformation documentCreationInfo, User user) throws TException { + assertUser(user); + assertNotNull(documentCreationInfo); + + return handler.createRequest(documentCreationInfo, user, false); + } + + @Override + public void createSpdxDocumentCreationInfoDeleteRequest(DocumentCreationInformation documentCreationInfo, User user) throws TException { + assertUser(user); + assertNotNull(documentCreationInfo); + + handler.createRequest(documentCreationInfo, user, true); + } + + @Override + public RequestStatus createSpdxPackageInfoRequest(PackageInformation packageInfo, User user) throws TException { + assertUser(user); + assertNotNull(packageInfo); + + return handler.createRequest(packageInfo, user, false); + } + + @Override + public void createSpdxPackageInfoDeleteRequest(PackageInformation packageInfo, User user) throws TException { + assertUser(user); + assertNotNull(packageInfo); + + handler.createRequest(packageInfo, user, true); + } + @Override public List getModerationRequestByDocumentId(String documentId) throws TException { assertId(documentId); diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ModerationDatabaseHandler.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ModerationDatabaseHandler.java index 36fa89e849..9e787f49b0 100644 --- a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ModerationDatabaseHandler.java +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ModerationDatabaseHandler.java @@ -24,6 +24,9 @@ import org.eclipse.sw360.datahandler.db.ComponentDatabaseHandler; import org.eclipse.sw360.datahandler.db.DatabaseHandlerUtil; import org.eclipse.sw360.datahandler.db.ProjectDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.document.SpdxDocumentDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo.SpdxDocumentCreationInfoDatabaseHandler; +import org.eclipse.sw360.datahandler.db.spdx.packageinfo.SpdxPackageInfoDatabaseHandler; import org.eclipse.sw360.datahandler.permissions.PermissionUtils; import org.eclipse.sw360.datahandler.thrift.ClearingRequestEmailTemplate; import org.eclipse.sw360.datahandler.thrift.ClearingRequestState; @@ -43,6 +46,9 @@ import org.eclipse.sw360.datahandler.thrift.projects.ClearingRequest; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.projects.ProjectClearingState; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; import org.eclipse.sw360.datahandler.thrift.users.User; import org.eclipse.sw360.datahandler.thrift.users.UserGroup; @@ -90,6 +96,9 @@ public class ModerationDatabaseHandler { private final LicenseDatabaseHandler licenseDatabaseHandler; private final ProjectDatabaseHandler projectDatabaseHandler; private final ComponentDatabaseHandler componentDatabaseHandler; + private final SpdxDocumentDatabaseHandler spdxDocumentDatabaseHandler; + private final SpdxDocumentCreationInfoDatabaseHandler spdxDocumentCreationInfoDatabaseHandler; + private final SpdxPackageInfoDatabaseHandler spdxPackageInfoDatabaseHandler; private final DatabaseConnectorCloudant db; private DatabaseHandlerUtil dbHandlerUtil; @@ -105,6 +114,9 @@ public ModerationDatabaseHandler(Supplier httpClient, String dbN licenseDatabaseHandler = new LicenseDatabaseHandler(httpClient, dbName); projectDatabaseHandler = new ProjectDatabaseHandler(httpClient, dbName, attachmentDbName); componentDatabaseHandler = new ComponentDatabaseHandler(httpClient, dbName, attachmentDbName); + spdxDocumentDatabaseHandler = new SpdxDocumentDatabaseHandler(httpClient, DatabaseSettings.COUCH_DB_SPDX); + spdxDocumentCreationInfoDatabaseHandler = new SpdxDocumentCreationInfoDatabaseHandler(httpClient, DatabaseSettings.COUCH_DB_SPDX); + spdxPackageInfoDatabaseHandler = new SpdxPackageInfoDatabaseHandler(httpClient, DatabaseSettings.COUCH_DB_SPDX); DatabaseConnectorCloudant dbChangeLogs = new DatabaseConnectorCloudant(httpClient, DatabaseSettings.COUCH_DB_CHANGE_LOGS); this.dbHandlerUtil = new DatabaseHandlerUtil(dbChangeLogs); } @@ -583,6 +595,80 @@ public void createRequest(User user) { addOrUpdate(request, user); } + private Set getSPDXDocumentModerators(String department, String createdBy) { + // Define moderators + Set moderators = new HashSet<>(); + CommonUtils.add(moderators, createdBy); + CommonUtils.addAll(moderators, getUsersAtLeast(UserGroup.ECC_ADMIN, department, false, true)); + CommonUtils.addAll(moderators, getUsersAtLeast(UserGroup.ADMIN)); + return moderators; + } + + public RequestStatus createRequest(SPDXDocument spdx, User user, Boolean isDeleteRequest) { + SPDXDocument dbSpdx; + try{ + dbSpdx = spdxDocumentDatabaseHandler.getSPDXDocumentById(spdx.getId(), user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Document from database. Could not generate moderation request.", e); + return RequestStatus.FAILURE; + } + // Define moderators + Set moderators = getSPDXDocumentModerators(user.getDepartment(), dbSpdx.getCreatedBy()); + ModerationRequest request = createStubRequest(user, isDeleteRequest, spdx.getId(), moderators); + + // Set meta-data + request.setDocumentType(DocumentType.SPDXDOCUMENT); + request.setDocumentName(SW360Utils.printName(spdx)); + + // Fill the request + ModerationRequestGenerator generator = new SpdxDocumentModerationRequestGenerator(); + request = generator.setAdditionsAndDeletions(request, spdx, dbSpdx); + addOrUpdate(request, user); + return RequestStatus.SENT_TO_MODERATOR; + } + + public RequestStatus createRequest(DocumentCreationInformation documentCreationInfo, User user, Boolean isDeleteRequest) { + DocumentCreationInformation dbDocumentCreationInfo; + try{ + dbDocumentCreationInfo = spdxDocumentCreationInfoDatabaseHandler.getDocumentCreationInformationById(documentCreationInfo.getId(), user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Document Creation Info from database. Could not generate moderation request.", e); + return RequestStatus.FAILURE; + } + // Define moderators + Set moderators = getSPDXDocumentModerators(user.getDepartment(), dbDocumentCreationInfo.getCreatedBy()); + ModerationRequest request = createStubRequest(user, isDeleteRequest, documentCreationInfo.getId(), moderators); + // Set meta-data + request.setDocumentType(DocumentType.SPDX_DOCUMENT_CREATION_INFO); + request.setDocumentName(SW360Utils.printName(documentCreationInfo)); + // Fill the request + ModerationRequestGenerator generator = new SpdxDocumentCreationInfoModerationRequestGenerator(); + request = generator.setAdditionsAndDeletions(request, documentCreationInfo, dbDocumentCreationInfo); + addOrUpdate(request, user); + return RequestStatus.SENT_TO_MODERATOR; + } + + public RequestStatus createRequest(PackageInformation packageInfo, User user, Boolean isDeleteRequest) { + PackageInformation dbPackageInfo; + try{ + dbPackageInfo = spdxPackageInfoDatabaseHandler.getPackageInformationById(packageInfo.getId(), user); + } catch (SW360Exception e) { + log.error("Could not get original SPDX Package Info from database. Could not generate moderation request.", e); + return RequestStatus.FAILURE; + } + // Define moderators + Set moderators = getSPDXDocumentModerators(user.getDepartment(), dbPackageInfo.getCreatedBy()); + ModerationRequest request = createStubRequest(user, isDeleteRequest, packageInfo.getId(), moderators); + // Set meta-data + request.setDocumentType(DocumentType.SPDX_PACKAGE_INFO); + request.setDocumentName(SW360Utils.printName(packageInfo)); + // Fill the request + ModerationRequestGenerator generator = new SpdxPackageInfoModerationRequestGenerator(); + request = generator.setAdditionsAndDeletions(request, packageInfo, dbPackageInfo); + addOrUpdate(request, user); + return RequestStatus.SENT_TO_MODERATOR; + } + private String getDepartmentByUserEmail(String userEmail) throws TException { UserService.Iface client = (new ThriftClients()).makeUserClient(); return client.getDepartmentByEmail(userEmail); diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ReleaseModerationRequestGenerator.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ReleaseModerationRequestGenerator.java index b868bfe792..0b61604f4e 100644 --- a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ReleaseModerationRequestGenerator.java +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/ReleaseModerationRequestGenerator.java @@ -24,8 +24,6 @@ */ public class ReleaseModerationRequestGenerator extends ModerationRequestGenerator { - private static final String DUMMY_VALUE = "Dummy_Value"; - @Override public ModerationRequest setAdditionsAndDeletions(ModerationRequest request, Release updateRelease, Release actualRelease){ updateDocument = updateRelease; @@ -34,13 +32,13 @@ public ModerationRequest setAdditionsAndDeletions(ModerationRequest request, Rel documentAdditions = new Release(); documentDeletions = new Release(); //required fields: - documentAdditions.setName(DUMMY_VALUE); + documentAdditions.setName(updateRelease.getName()); documentAdditions.setId(updateRelease.getId()); - documentAdditions.setVersion(DUMMY_VALUE); + documentAdditions.setVersion(updateRelease.getVersion()); documentAdditions.setComponentId(updateRelease.getComponentId()); - documentDeletions.setName(DUMMY_VALUE); + documentDeletions.setName(actualRelease.getName()); documentDeletions.setId(actualRelease.getId()); - documentDeletions.setVersion(DUMMY_VALUE); + documentDeletions.setVersion(actualRelease.getVersion()); documentDeletions.setComponentId(actualRelease.getComponentId()); for (Release._Fields field : Release._Fields.values()) { diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentCreationInfoModerationRequestGenerator.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentCreationInfoModerationRequestGenerator.java new file mode 100644 index 0000000000..3438b19e69 --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentCreationInfoModerationRequestGenerator.java @@ -0,0 +1,48 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.moderation.db; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; + +public class SpdxDocumentCreationInfoModerationRequestGenerator extends ModerationRequestGenerator { + @Override + public ModerationRequest setAdditionsAndDeletions(ModerationRequest request, DocumentCreationInformation updateDocumentCreationInfo, DocumentCreationInformation actualDocumentCreationInfo){ + updateDocument = updateDocumentCreationInfo; + actualDocument = actualDocumentCreationInfo; + + documentAdditions = new DocumentCreationInformation(); + documentDeletions = new DocumentCreationInformation(); + //required fields: + documentAdditions.setId(updateDocument.getId()); + documentDeletions.setId(actualDocument.getId()); + for (DocumentCreationInformation._Fields field : DocumentCreationInformation._Fields.values()) { + + if(actualDocument.getFieldValue(field) == null){ + documentAdditions.setFieldValue(field, updateDocument.getFieldValue(field)); + } else if (updateDocument.getFieldValue(field) == null){ + documentDeletions.setFieldValue(field, actualDocument.getFieldValue(field)); + } else if(!actualDocument.getFieldValue(field).equals(updateDocument.getFieldValue(field))) { + switch (field) { + case PERMISSIONS: + case DOCUMENT_STATE: + case CREATED_BY: + break; + default: + dealWithBaseTypes(field, DocumentCreationInformation.metaDataMap.get(field)); + } + } + } + request.setDocumentCreationInfoAdditions(documentAdditions); + request.setDocumentCreationInfoDeletions(documentDeletions); + return request; + } +} diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentModerationRequestGenerator.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentModerationRequestGenerator.java new file mode 100644 index 0000000000..08bf1f538b --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentModerationRequestGenerator.java @@ -0,0 +1,49 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.moderation.db; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; + +public class SpdxDocumentModerationRequestGenerator extends ModerationRequestGenerator { + @Override + public ModerationRequest setAdditionsAndDeletions(ModerationRequest request, SPDXDocument updateSpdx, SPDXDocument actualSpdx){ + updateDocument = updateSpdx; + actualDocument = actualSpdx; + + documentAdditions = new SPDXDocument(); + documentDeletions = new SPDXDocument(); + //required fields: + documentAdditions.setId(updateSpdx.getId()); + documentDeletions.setId(actualSpdx.getId()); + + for (SPDXDocument._Fields field : SPDXDocument._Fields.values()) { + + if(actualSpdx.getFieldValue(field) == null){ + documentAdditions.setFieldValue(field, updateSpdx.getFieldValue(field)); + } else if (updateSpdx.getFieldValue(field) == null){ + documentDeletions.setFieldValue(field, actualSpdx.getFieldValue(field)); + } else if(!actualSpdx.getFieldValue(field).equals(updateSpdx.getFieldValue(field))) { + switch (field) { + case PERMISSIONS: + case DOCUMENT_STATE: + case CREATED_BY: + break; + default: + dealWithBaseTypes(field, SPDXDocument.metaDataMap.get(field)); + } + } + } + request.setSPDXDocumentAdditions(documentAdditions); + request.setSPDXDocumentDeletions(documentDeletions); + return request; + } +} diff --git a/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxPackageInfoModerationRequestGenerator.java b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxPackageInfoModerationRequestGenerator.java new file mode 100644 index 0000000000..5be9d6ee2a --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxPackageInfoModerationRequestGenerator.java @@ -0,0 +1,52 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.moderation.db; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; +import org.apache.thrift.protocol.TType; +public class SpdxPackageInfoModerationRequestGenerator extends ModerationRequestGenerator { + @Override + public ModerationRequest setAdditionsAndDeletions(ModerationRequest request, PackageInformation updatePackageInfo, PackageInformation actualPackageInfo){ + updateDocument = updatePackageInfo; + actualDocument = actualPackageInfo; + + documentAdditions = new PackageInformation(); + documentDeletions = new PackageInformation(); + //required fields: + documentAdditions.setId(updateDocument.getId()); + documentDeletions.setId(actualDocument.getId()); + + for (PackageInformation._Fields field : PackageInformation._Fields.values()) { + if(PackageInformation.metaDataMap.get(field).valueMetaData.type == TType.BOOL && + actualDocument.getFieldValue(field) != updateDocument.getFieldValue(field)) { + documentAdditions.setFieldValue(field, updateDocument.getFieldValue(field)); + documentDeletions.setFieldValue(field, actualDocument.getFieldValue(field)); + } else if(actualDocument.getFieldValue(field) == null){ + documentAdditions.setFieldValue(field, updateDocument.getFieldValue(field)); + } else if (updateDocument.getFieldValue(field) == null){ + documentDeletions.setFieldValue(field, actualDocument.getFieldValue(field)); + } else if(!actualDocument.getFieldValue(field).equals(updateDocument.getFieldValue(field))) { + switch (field) { + case PERMISSIONS: + case DOCUMENT_STATE: + case CREATED_BY: + break; + default: + dealWithBaseTypes(field, PackageInformation.metaDataMap.get(field)); + } + } + } + request.setPackageInfoAdditions(documentAdditions); + request.setPackageInfoDeletions(documentDeletions); + return request; + } +} diff --git a/backend/src/src-spdxdocument/pom.xml b/backend/src/src-spdxdocument/pom.xml new file mode 100644 index 0000000000..a44a2789eb --- /dev/null +++ b/backend/src/src-spdxdocument/pom.xml @@ -0,0 +1,38 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-src + ${revision} + + + src-spdxdocument + jar + src-spdxdocument + + + + org.apache.logging.log4j + log4j-1.2-api + + + org.apache.commons + commons-lang3 + + + diff --git a/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentHandler.java b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentHandler.java new file mode 100644 index 0000000000..863c91d60e --- /dev/null +++ b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentHandler.java @@ -0,0 +1,90 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxdocument; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import org.eclipse.sw360.datahandler.db.spdx.document.*; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.AddDocumentRequestSummary; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import com.cloudant.client.api.CloudantClient; + +import org.apache.thrift.TException; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.common.SW360Assert.*; + +public class SPDXDocumentHandler implements SPDXDocumentService.Iface { + + SpdxDocumentDatabaseHandler handler; + + SPDXDocumentHandler() throws MalformedURLException { + handler = new SpdxDocumentDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + } + + SPDXDocumentHandler(Supplier httpClient, String dbName) throws MalformedURLException { + handler = new SpdxDocumentDatabaseHandler(httpClient, dbName); + } + + @Override + public List getSPDXDocumentSummary(User user) throws TException { + assertUser(user); + return handler.getSPDXDocumentSummary(user); + } + + @Override + public SPDXDocument getSPDXDocumentById(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getSPDXDocumentById(id, user); + } + + @Override + public SPDXDocument getSPDXDocumentForEdit(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getSPDXDocumentForEdit(id, user); + } + + @Override + public AddDocumentRequestSummary addSPDXDocument(SPDXDocument spdx, User user) throws TException { + assertNotNull(spdx); + assertUser(user); + return handler.addSPDXDocument(spdx, user); + } + + @Override + public RequestStatus updateSPDXDocument(SPDXDocument spdx, User user) throws TException { + assertNotNull(spdx); + assertUser(user); + return handler.updateSPDXDocument(spdx, user); + } + + @Override + public RequestStatus updateSPDXDocumentFromModerationRequest(SPDXDocument spdxAdditions, SPDXDocument spdxDeletions, User user) throws TException { + assertUser(user); + return handler.updateSPDXDocumentFromModerationRequest(spdxAdditions, spdxDeletions, user); + } + + @Override + public RequestStatus deleteSPDXDocument(String id, User user) throws TException { + assertId(id); + assertUser(user); + + return handler.deleteSPDXDocument(id, user); + } + +} \ No newline at end of file diff --git a/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentServlet.java b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentServlet.java new file mode 100644 index 0000000000..5d47b0d199 --- /dev/null +++ b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentServlet.java @@ -0,0 +1,26 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxdocument; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocumentService; +import org.apache.thrift.protocol.TCompactProtocol; +import org.eclipse.sw360.projects.Sw360ThriftServlet; + +import java.net.MalformedURLException; + +public class SPDXDocumentServlet extends Sw360ThriftServlet { + + public SPDXDocumentServlet() throws MalformedURLException { + // Create a service processor using the provided handler + super(new SPDXDocumentService.Processor<>(new SPDXDocumentHandler()), new TCompactProtocol.Factory()); + } + +} diff --git a/backend/src/src-spdxdocumentcreationinfo/pom.xml b/backend/src/src-spdxdocumentcreationinfo/pom.xml new file mode 100644 index 0000000000..145d3c4166 --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-src + ${revision} + + + src-spdxdocumentcreationinfo + jar + src-spdxdocumentcreationinfo + + + + org.apache.logging.log4j + log4j-1.2-api + + + org.apache.commons + commons-lang3 + + + org.eclipse.sw360 + src-spdxdocument + ${project.version} + + + diff --git a/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationHandler.java b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationHandler.java new file mode 100644 index 0000000000..681ad0d52e --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationHandler.java @@ -0,0 +1,90 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxdocumentcreationinfo; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import org.eclipse.sw360.datahandler.db.spdx.documentcreationinfo.*; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.AddDocumentRequestSummary; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import com.cloudant.client.api.CloudantClient; + +import org.apache.thrift.TException; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.common.SW360Assert.*; + +public class DocumentCreationInformationHandler implements DocumentCreationInformationService.Iface { + + SpdxDocumentCreationInfoDatabaseHandler handler; + + DocumentCreationInformationHandler() throws MalformedURLException { + handler = new SpdxDocumentCreationInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + } + + DocumentCreationInformationHandler(Supplier httpClient, String dbName) throws MalformedURLException { + handler = new SpdxDocumentCreationInfoDatabaseHandler(httpClient, dbName); + } + + @Override + public List getDocumentCreationInformationSummary(User user) throws TException { + assertUser(user); + return handler.getDocumentCreationInformationSummary(user); + } + + @Override + public DocumentCreationInformation getDocumentCreationInformationById(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getDocumentCreationInformationById(id, user); + } + + @Override + public DocumentCreationInformation getDocumentCreationInfoForEdit(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getDocumentCreationInfoForEdit(id, user); + } + + @Override + public AddDocumentRequestSummary addDocumentCreationInformation(DocumentCreationInformation documentCreationInformation, User user) throws TException { + assertNotNull(documentCreationInformation); + assertUser(user); + return handler.addDocumentCreationInformation(documentCreationInformation, user); + } + + @Override + public RequestStatus updateDocumentCreationInformation(DocumentCreationInformation documentCreationInformation, User user) throws TException { + assertNotNull(documentCreationInformation); + assertUser(user); + return handler.updateDocumentCreationInformation(documentCreationInformation, user); + } + + @Override + public RequestStatus updateDocumentCreationInfomationFromModerationRequest(DocumentCreationInformation documentCreationInfoAdditions, DocumentCreationInformation documentCreationInfoDeletions, User user) throws TException { + assertUser(user); + return handler.updateDocumentCreationInfomationFromModerationRequest(documentCreationInfoAdditions, documentCreationInfoDeletions, user); + } + + @Override + public RequestStatus deleteDocumentCreationInformation(String id, User user) throws TException { + assertId(id); + assertUser(user); + + return handler.deleteDocumentCreationInformation(id, user); + } + +} \ No newline at end of file diff --git a/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationServlet.java b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationServlet.java new file mode 100644 index 0000000000..43dd71d85d --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationServlet.java @@ -0,0 +1,26 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxdocumentcreationinfo; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformationService; +import org.apache.thrift.protocol.TCompactProtocol; +import org.eclipse.sw360.projects.Sw360ThriftServlet; + +import java.net.MalformedURLException; + +public class DocumentCreationInformationServlet extends Sw360ThriftServlet { + + public DocumentCreationInformationServlet() throws MalformedURLException { + // Create a service processor using the provided handler + super(new DocumentCreationInformationService.Processor<>(new DocumentCreationInformationHandler()), new TCompactProtocol.Factory()); + } + +} \ No newline at end of file diff --git a/backend/src/src-spdxpackageinfo/pom.xml b/backend/src/src-spdxpackageinfo/pom.xml new file mode 100644 index 0000000000..54630aeef5 --- /dev/null +++ b/backend/src/src-spdxpackageinfo/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-src + ${revision} + + + src-spdxpackageinfo + jar + src-spdxpackageinfo + + + + org.apache.logging.log4j + log4j-1.2-api + + + org.apache.commons + commons-lang3 + + + org.eclipse.sw360 + src-spdxdocument + ${project.version} + + + diff --git a/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationHandler.java b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationHandler.java new file mode 100644 index 0000000000..ff7747dd03 --- /dev/null +++ b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxpackageinfo; + +import org.eclipse.sw360.datahandler.common.DatabaseSettings; +import org.eclipse.sw360.datahandler.db.spdx.packageinfo.*; +import org.eclipse.sw360.datahandler.thrift.RequestStatus; +import org.eclipse.sw360.datahandler.thrift.RequestSummary; +import org.eclipse.sw360.datahandler.thrift.AddDocumentRequestSummary; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import com.cloudant.client.api.CloudantClient; + +import org.apache.thrift.TException; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; + +import static org.eclipse.sw360.datahandler.common.SW360Assert.*; + +public class PackageInformationHandler implements PackageInformationService.Iface { + + SpdxPackageInfoDatabaseHandler handler; + + PackageInformationHandler() throws MalformedURLException { + handler = new SpdxPackageInfoDatabaseHandler(DatabaseSettings.getConfiguredClient(), DatabaseSettings.COUCH_DB_SPDX); + } + + PackageInformationHandler(Supplier httpClient, String dbName) throws MalformedURLException { + handler = new SpdxPackageInfoDatabaseHandler(httpClient, dbName); + } + + @Override + public List getPackageInformationSummary(User user) throws TException { + assertUser(user); + return handler.getPackageInformationSummary(user); + } + + @Override + public PackageInformation getPackageInformationById(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getPackageInformationById(id, user); + } + + @Override + public PackageInformation getPackageInformationForEdit(String id, User user) throws TException { + assertNotEmpty(id); + assertUser(user); + return handler.getPackageInformationForEdit(id, user); + } + + @Override + public AddDocumentRequestSummary addPackageInformation(PackageInformation packageInformation, User user) throws TException { + assertNotNull(packageInformation); + assertUser(user); + return handler.addPackageInformation(packageInformation, user); + } + + @Override + public AddDocumentRequestSummary addPackageInformations(Set packageInformations, User user) throws TException { + return handler.addPackageInformations(packageInformations, user); + } + + @Override + public RequestStatus updatePackageInformation(PackageInformation packageInformation, User user) throws TException { + assertNotNull(packageInformation); + assertUser(user); + return handler.updatePackageInformation(packageInformation, user); + } + + @Override + public RequestSummary updatePackageInformations(Set packageInformations, User user) throws TException { + assertUser(user); + return handler.updatePackageInformations(packageInformations, user); + } + + @Override + public RequestStatus updatePackageInfomationFromModerationRequest(PackageInformation packageInfoAdditions, PackageInformation packageInfoDeletions, User user) throws TException { + assertUser(user); + return handler.updatePackageInfomationFromModerationRequest(packageInfoAdditions, packageInfoDeletions, user); + } + @Override + public RequestStatus deletePackageInformation(String id, User user) throws TException { + assertId(id); + assertUser(user); + + return handler.deletePackageInformation(id, user); + } + +} \ No newline at end of file diff --git a/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationServlet.java b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationServlet.java new file mode 100644 index 0000000000..8e1ea3b065 --- /dev/null +++ b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationServlet.java @@ -0,0 +1,26 @@ +/* + * Copyright TOSHIBA CORPORATION, 2022. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2022. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.spdxpackageinfo; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformationService; +import org.apache.thrift.protocol.TCompactProtocol; +import org.eclipse.sw360.projects.Sw360ThriftServlet; + +import java.net.MalformedURLException; + +public class PackageInformationServlet extends Sw360ThriftServlet { + + public PackageInformationServlet() throws MalformedURLException { + // Create a service processor using the provided handler + super(new PackageInformationService.Processor<>(new PackageInformationHandler()), new TCompactProtocol.Factory()); + } + +} \ No newline at end of file diff --git a/backend/svc/pom.xml b/backend/svc/pom.xml index dece8b6a20..e28c66a908 100644 --- a/backend/svc/pom.xml +++ b/backend/svc/pom.xml @@ -41,6 +41,9 @@ svc-wsimport svc-changelogs svc-health + svc-spdxdocument + svc-spdxdocumentcreationinfo + svc-spdxpackageinfo diff --git a/backend/svc/svc-spdxdocument/pom.xml b/backend/svc/svc-spdxdocument/pom.xml new file mode 100644 index 0000000000..f1e8a1f9d4 --- /dev/null +++ b/backend/svc/svc-spdxdocument/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-svc + ${revision} + + + svc-spdxdocument + war + svc-spdxdocument + + + ${backend.deploy.dir} + + + + spdxdocument + + + + maven-dependency-plugin + + + add-build-configuration-resources + generate-resources + + unpack + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + true + ${project.build.outputDirectory} + **/*.java,**/*.class + + + + + + + + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + + + diff --git a/backend/svc/svc-spdxdocument/src/main/webapp/WEB-INF/web.xml b/backend/svc/svc-spdxdocument/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..342103bfaa --- /dev/null +++ b/backend/svc/svc-spdxdocument/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ + + + + SPDX Document Service + + index.jsp + + + + org.eclipse.sw360.SW360ServiceContextListener + + + + SPDXDocumentService + org.eclipse.sw360.spdxdocument.SPDXDocumentServlet + 1 + + + + SPDXDocumentService + /thrift + + + \ No newline at end of file diff --git a/backend/svc/svc-spdxdocument/src/main/webapp/index.jsp b/backend/svc/svc-spdxdocument/src/main/webapp/index.jsp new file mode 100644 index 0000000000..729fcde010 --- /dev/null +++ b/backend/svc/svc-spdxdocument/src/main/webapp/index.jsp @@ -0,0 +1,21 @@ + +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Welcome to the SW360 SPDX Document Service + + +

Welcome to the SW360 SPDX Document Service!

+ + diff --git a/backend/svc/svc-spdxdocumentcreationinfo/pom.xml b/backend/svc/svc-spdxdocumentcreationinfo/pom.xml new file mode 100644 index 0000000000..d2bc99fc7f --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-svc + ${revision} + + + svc-spdxdocumentcreationinfo + war + svc-spdxdocumentcreationinfo + + + ${backend.deploy.dir} + + + + spdxdocumentcreationinfo + + + + maven-dependency-plugin + + + add-build-configuration-resources + generate-resources + + unpack + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + true + ${project.build.outputDirectory} + **/*.java,**/*.class + + + + + + + + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + + + diff --git a/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/WEB-INF/web.xml b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..6c3ed4e9d3 --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ + + + + SPDX Document Creation Information Service + + index.jsp + + + + org.eclipse.sw360.SW360ServiceContextListener + + + + DocumentCreationInformationService + org.eclipse.sw360.spdxdocumentcreationinfo.DocumentCreationInformationServlet + 1 + + + + DocumentCreationInformationService + /thrift + + + \ No newline at end of file diff --git a/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/index.jsp b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/index.jsp new file mode 100644 index 0000000000..12d306ffae --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/index.jsp @@ -0,0 +1,21 @@ + +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Welcome to the SW360 SPDX Document Creation Information Service + + +

Welcome to the SW360 SPDX Document Creation Information Service!

+ + diff --git a/backend/svc/svc-spdxpackageinfo/pom.xml b/backend/svc/svc-spdxpackageinfo/pom.xml new file mode 100644 index 0000000000..ac4d20b937 --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + + org.eclipse.sw360 + backend-svc + ${revision} + + + svc-spdxpackageinfo + war + svc-spdxpackageinfo + + + ${backend.deploy.dir} + + + + spdxpackageinfo + + + + maven-dependency-plugin + + + add-build-configuration-resources + generate-resources + + unpack + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + true + ${project.build.outputDirectory} + **/*.java,**/*.class + + + + + + + + + + + + org.eclipse.sw360 + src-${project.build.finalName} + ${project.version} + jar + + + diff --git a/backend/svc/svc-spdxpackageinfo/src/main/webapp/WEB-INF/web.xml b/backend/svc/svc-spdxpackageinfo/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..c11223b402 --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,38 @@ + + + + SPDX Package Information Service + + index.jsp + + + + org.eclipse.sw360.SW360ServiceContextListener + + + + PackageInformationService + org.eclipse.sw360.spdxpackageinfo.PackageInformationServlet + 1 + + + + PackageInformationService + /thrift + + + \ No newline at end of file diff --git a/backend/svc/svc-spdxpackageinfo/src/main/webapp/index.jsp b/backend/svc/svc-spdxpackageinfo/src/main/webapp/index.jsp new file mode 100644 index 0000000000..313504d7e8 --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/src/main/webapp/index.jsp @@ -0,0 +1,21 @@ + +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Welcome to the SW360 SPDX Package Information Service + + +

Welcome to the SW360 SPDX Package Information Service!

+ + diff --git a/build-configuration/test-resources/couchdb-test.properties b/build-configuration/test-resources/couchdb-test.properties index 4bc303fb06..ce99b80782 100644 --- a/build-configuration/test-resources/couchdb-test.properties +++ b/build-configuration/test-resources/couchdb-test.properties @@ -8,7 +8,7 @@ # SPDX-License-Identifier: EPL-2.0 # -# N.B this is the build property file, copied from module build-configuration +# N.B this is the build property file, copied from module build-configurationshould_document_get_projects_releases couchdb.url = http://localhost:5984 couchdb.user = diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/ChangeLogsPortletUtils.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/ChangeLogsPortletUtils.java index 3da089e1a9..a3176b23d2 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/ChangeLogsPortletUtils.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/ChangeLogsPortletUtils.java @@ -22,6 +22,7 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.Set; import javax.portlet.PortletRequest; import javax.portlet.ResourceRequest; @@ -38,6 +39,10 @@ import org.eclipse.sw360.datahandler.thrift.changelogs.ChangeLogs; import org.eclipse.sw360.datahandler.thrift.changelogs.ChangeLogsService; import org.eclipse.sw360.datahandler.thrift.changelogs.ChangeLogsService.Iface; +import org.eclipse.sw360.datahandler.thrift.components.ComponentService; +import org.eclipse.sw360.datahandler.thrift.components.Release; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocumentService; import org.eclipse.sw360.datahandler.thrift.changelogs.ChangedFields; import org.eclipse.sw360.datahandler.thrift.changelogs.ReferenceDocData; import org.eclipse.sw360.datahandler.thrift.users.User; @@ -128,8 +133,12 @@ private JSONObject serveChangeLogsList(ResourceRequest request, ResourceResponse } } - List changeLogsList = getFilteredChangeLogList(request, changeLogsClient); + List changeLogsList = getFilteredChangeLogList(request, changeLogsClient, null); + if (isReleaseChangesLog(changeLogsList)) { + changeLogsList = getChangesLogsForSPDX(request, changeLogsList, changeLogsClient); + } + changeLogsList.stream().forEach(cl -> cl.setChangeTimestamp(cl.getChangeTimestamp().split(" ")[0])); JSONArray jsonProjects = getChangeLogData(changeLogsList, paginationParameters, request); JSONObject jsonResult = createJSONObject(); jsonResult.put(DATATABLE_RECORDS_TOTAL, changeLogsList.size()); @@ -139,6 +148,49 @@ private JSONObject serveChangeLogsList(ResourceRequest request, ResourceResponse return jsonResult; } + private boolean isReleaseChangesLog(List changeLogsList) { + for (ChangeLogs changeLogs : changeLogsList) { + if (changeLogs.documentType.equals("release")){ + return true; + } + } + return false; + } + + private List getChangesLogsForSPDX(ResourceRequest request, List SPDXChangeLogsList, ChangeLogsService.Iface changeLogsClient) { + ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + SPDXDocumentService.Iface SPDXClient = thriftClients.makeSPDXClient(); + User user = UserCacheHolder.getUserFromRequest(request); + String releaseId = request.getParameter(PortalConstants.DOCUMENT_ID); + try { + Release release = componentClient.getReleaseById(releaseId, user); + String spdxId = release.getSpdxId(); + if (!isNullOrEmpty(spdxId)) { + SPDXDocument spdxDocument = SPDXClient.getSPDXDocumentById(spdxId, user); + String spdxDocumentCreationInfoId = spdxDocument.getSpdxDocumentCreationInfoId(); + Set packageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + List spdxChangeLogsList = getFilteredChangeLogList(request, changeLogsClient, spdxId); + SPDXChangeLogsList.addAll(spdxChangeLogsList); + if (!isNullOrEmpty(spdxDocumentCreationInfoId)) { + List spdxDocumentChangeLogsList = getFilteredChangeLogList(request, changeLogsClient, spdxDocumentCreationInfoId); + SPDXChangeLogsList.addAll(spdxDocumentChangeLogsList); + } + if (packageInfoIds != null) { + List packagesChangeLogsList = Lists.newArrayList(); + for (String packageInfoId : packageInfoIds) { + List packageChangeLogsList = getFilteredChangeLogList(request, changeLogsClient, packageInfoId); + packagesChangeLogsList.addAll(packageChangeLogsList); + } + SPDXChangeLogsList.addAll(packagesChangeLogsList); + } + Collections.sort(SPDXChangeLogsList, Comparator.comparing(ChangeLogs::getChangeTimestamp).reversed()); + } + } catch (TException e) { + log.error("Error while getting change logs for SPDX" + e); + } + return SPDXChangeLogsList; + } + private LiferayPortletURL getModerationPortletUrl(PortletRequest request) { Portlet portlet = PortletLocalServiceUtil.getPortletById(PortalConstants.MODERATION_PORTLET_NAME); Optional layout = LayoutLocalServiceUtil.getLayouts(portlet.getCompanyId()).stream() @@ -154,9 +206,11 @@ private LiferayPortletURL getModerationPortletUrl(PortletRequest request) { } private List getFilteredChangeLogList(ResourceRequest request, - ChangeLogsService.Iface changeLogsClient) { + ChangeLogsService.Iface changeLogsClient, String docId) { final User user = UserCacheHolder.getUserFromRequest(request); - String docId = request.getParameter(PortalConstants.DOCUMENT_ID); + if (docId == null) { + docId = request.getParameter(PortalConstants.DOCUMENT_ID); + } try { return changeLogsClient.getChangeLogsByDocumentId(user, docId); } catch (TException exp) { diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java index 342e656b70..7300579205 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java @@ -304,7 +304,6 @@ public class PortalConstants { public static final String PROJECT_OBLIGATIONS_INFO_BY_RELEASE = "projectObligationsInfoByRelease"; public static final String LINKED_OBLIGATIONS = "linkedObligations"; public static final String APPROVED_OBLIGATIONS_COUNT = "approvedObligationsCount"; - public static final String OBLIGATION_FROM_README_OSS = "obligationFromReadmeOSS"; public static final String EXCLUDED_RELEASES = "excludedReleases"; public static final String RELATIONSHIPS = "relations"; public static final String PROJECT_RELEASE_TO_RELATION = "projectReleaseToRelation"; @@ -500,7 +499,11 @@ public class PortalConstants { public static final String PARENT_SCOPE_GROUP_ID = "parentScopeGroupId"; // bom import + public static final String PREPARE_IMPORT_BOM = "prepareImportBom"; public static final String IMPORT_BOM = "importBom"; + public static final String IMPORT_BOM_AS_NEW = "importBomAsNew"; + public static final String NEW_RELEASE_VERSION = "newRleaseVersion"; + public static final String RDF_FILE_PATH = "rdfFilePath"; // project actions public static final String VIEW_LINKED_PROJECTS = "view_linked_projects"; @@ -658,6 +661,18 @@ public class PortalConstants { public static final boolean SSO_LOGIN_ENABLED; public static final boolean IS_COMPONENT_VISIBILITY_RESTRICTION_ENABLED; + //! Specialized keys for SPDX + public static final String SPDXDOCUMENT = "spdxDocument"; + public static final String SPDX_DOCUMENT_CREATION_INFO = "spdxDocumentCreationInfo"; + public static final String SPDX_PACKAGE_INFO = "spdxPackageInfo"; + public static final String SPDX_DOCUMENT_ID = "spdxDocumentId"; + public static final String SPDX_DOCUMENT_CREATION_INFO_ID = "spdxDocumentCreationInfoId"; + public static final String SPDX_PACKAGE_INFO_ID = "spdxPackageInfoId"; + public static final String ACTUAL_SPDXDOCUMENT = "actual_SPDXDocument"; + public static final String ACTUAL_DOCUMENT_CREATION_INFO = "actual_DocumentCreationInfo"; + public static final String ACTUAL_PACKAGE_INFO = "actual_PackageInfo"; + public static final Set SET_RELATIONSHIP_TYPE; + static { Properties props = CommonUtils.loadProperties(PortalConstants.class, PROPERTIES_FILE_PATH); @@ -696,6 +711,7 @@ public class PortalConstants { CLEARING_REPORT_TEMPLATE_FORMAT = props.getProperty("org.eclipse.sw360.licensinfo.projectclearing.templateformat", "docx"); PREDEFINED_TAGS = props.getProperty("project.tag", "[]"); SSO_LOGIN_ENABLED = Boolean.parseBoolean(props.getProperty("sso.login.enabled", "false")); + SET_RELATIONSHIP_TYPE = CommonUtils.splitToSet(props.getProperty("relationship.type", "DESCRIBES,DESCRIBED_BY,CONTAINS,CONTAINED_BY,DEPENDS_ON,DEPENDENCY_OF,DEPENDENCY_MANIFEST_OF,BUILD_DEPENDENCY_OF,DEV_DEPENDENCY_OF,OPTIONAL_DEPENDENCY_OF,PROVIDED_DEPENDENCY_OF,TEST_DEPENDENCY_OF,RUNTIME_DEPENDENCY_OF,EXAMPLE_OF,GENERATES,GENERATED_FROM,ANCESTOR_OF,DESCENDANT_OF,VARIANT_OF,DISTRIBUTION_ARTIFACT,PATCH_FOR,PATCH_APPLIED,COPY_OF,FILE_ADDED,FILE_DELETED,FILE_MODIFIED,EXPANDED_FROM_ARCHIVE,DYNAMIC_LINK,STATIC_LINK,DATA_FILE_OF,TEST_CASE_OF,BUILD_TOOL_OF,DEV_TOOL_OF,TEST_OF,TEST_TOOL_OF,DOCUMENTATION_OF,OPTIONAL_COMPONENT_OF,METAFILE_OF,PACKAGE_OF,AMENDS,PREREQUISITE_FOR,HAS_PREREQUISITE,OTHER")); IS_COMPONENT_VISIBILITY_RESTRICTION_ENABLED = Boolean.parseBoolean( System.getProperty("RunComponentVisibilityRestrictionTest", props.getProperty("component.visibility.restriction.enabled", "false"))); DISABLE_CLEARING_REQUEST_FOR_PROJECT_WITH_GROUPS = props.getProperty("org.eclipse.sw360.disable.clearing.request.for.project.group", ""); diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/Sw360Portlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/Sw360Portlet.java index 4e6e4b3684..dba636fbc4 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/Sw360Portlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/Sw360Portlet.java @@ -152,6 +152,27 @@ protected void renderRequestSummary(PortletRequest request, MimeResponse respons } } + protected void renderRequestPreparation(PortletRequest request, MimeResponse response, ImportBomRequestPreparation requestPreparation) { + JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); + jsonObject.put(PortalConstants.RESULT, requestPreparation.requestStatus.toString()); + if (requestPreparation.isSetIsComponentDuplicate()) + jsonObject.put("isComponentDuplicate", requestPreparation.isComponentDuplicate); + if (requestPreparation.isSetIsReleaseDuplicate()) + jsonObject.put("isReleaseDuplicate", requestPreparation.isReleaseDuplicate); + if (requestPreparation.isSetName()) + jsonObject.put("name", requestPreparation.name); + if (requestPreparation.isSetVersion()) + jsonObject.put("version", requestPreparation.version); + if (requestPreparation.isSetMessage()) + jsonObject.put("message", requestPreparation.message); + + try { + writeJSON(request, response, jsonObject); + } catch (IOException e) { + log.error("Problem rendering RequestStatus", e); + } + } + protected void renderRequestStatus(PortletRequest request, MimeResponse response, RequestStatus requestStatus) { JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); jsonObject.put(PortalConstants.RESULT, requestStatus.toString()); diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/ComponentPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/ComponentPortlet.java index 1a4896c0bf..65a3087fad 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/ComponentPortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/ComponentPortlet.java @@ -12,10 +12,12 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; +import com.google.common.base.Predicate; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.liferay.portal.kernel.json.JSONArray; @@ -59,11 +61,16 @@ import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.vendors.VendorService; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation._Fields; import org.eclipse.sw360.exporter.ComponentExporter; import org.eclipse.sw360.portal.common.*; import org.eclipse.sw360.portal.common.datatables.PaginationParser; import org.eclipse.sw360.portal.common.datatables.data.PaginationParameters; import org.eclipse.sw360.portal.portlets.FossologyAwarePortlet; +import org.eclipse.sw360.portal.portlets.components.spdx.SpdxPortlet; import org.eclipse.sw360.portal.users.LifeRayUserSession; import org.eclipse.sw360.portal.users.UserCacheHolder; import org.eclipse.sw360.portal.users.UserUtils; @@ -75,6 +82,9 @@ import org.osgi.service.component.annotations.ConfigurationPolicy; import org.apache.commons.lang.StringUtils; +import java.nio.file.Files; +import java.nio.file.Paths; + import javax.portlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -101,24 +111,26 @@ import static org.eclipse.sw360.portal.common.PortletUtils.getVerificationState; import org.apache.thrift.transport.TTransportException; +import org.apache.thrift.protocol.TType; +import org.apache.xmlbeans.impl.common.SniffedXmlInputStream; @org.osgi.service.component.annotations.Component( - immediate = true, - properties = { - "/org/eclipse/sw360/portal/portlets/base.properties", - "/org/eclipse/sw360/portal/portlets/default.properties" - }, - property = { - "javax.portlet.name=" + COMPONENT_PORTLET_NAME, - - "javax.portlet.display-name=Components", - "javax.portlet.info.short-title=Components", - "javax.portlet.info.title=Components", - "javax.portlet.resource-bundle=content.Language", - "javax.portlet.init-param.view-template=/html/components/view.jsp", - }, - service = Portlet.class, - configurationPolicy = ConfigurationPolicy.REQUIRE + immediate = true, + properties = { + "/org/eclipse/sw360/portal/portlets/base.properties", + "/org/eclipse/sw360/portal/portlets/default.properties" + }, + property = { + "javax.portlet.name=" + COMPONENT_PORTLET_NAME, + + "javax.portlet.display-name=Components", + "javax.portlet.info.short-title=Components", + "javax.portlet.info.title=Components", + "javax.portlet.resource-bundle=content.Language", + "javax.portlet.init-param.view-template=/html/components/view.jsp", + }, + service = Portlet.class, + configurationPolicy = ConfigurationPolicy.REQUIRE ) public class ComponentPortlet extends FossologyAwarePortlet { @@ -180,6 +192,8 @@ protected Set getAttachments(String documentId, String documentType, private static final String CONFIG_KEY_URL = "url"; + private _Fields field; + //! Serve resource and helpers @Override public void serveResource(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { @@ -209,13 +223,13 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th serveLinkedReleases(request, response); } else if (PortalConstants.PROJECT_SEARCH.equals(action)) { serveProjectSearch(request, response); - } else if (PortalConstants.UPDATE_VULNERABILITIES_RELEASE.equals(action)){ - updateVulnerabilitiesRelease(request,response); - } else if (PortalConstants.UPDATE_VULNERABILITIES_COMPONENT.equals(action)){ - updateVulnerabilitiesComponent(request,response); + } else if (PortalConstants.UPDATE_VULNERABILITIES_RELEASE.equals(action)) { + updateVulnerabilitiesRelease(request, response); + } else if (PortalConstants.UPDATE_VULNERABILITIES_COMPONENT.equals(action)) { + updateVulnerabilitiesComponent(request, response); } else if (PortalConstants.UPDATE_ALL_VULNERABILITIES.equals(action)) { updateAllVulnerabilities(request, response); - } else if (PortalConstants.UPDATE_VULNERABILITY_VERIFICATION.equals(action)){ + } else if (PortalConstants.UPDATE_VULNERABILITY_VERIFICATION.equals(action)) { updateVulnerabilityVerification(request, response); } else if (PortalConstants.EXPORT_TO_EXCEL.equals(action)) { exportExcel(request, response); @@ -229,10 +243,14 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th loadSpdxLicenseInfo(request, response); } else if (PortalConstants.WRITE_SPDX_LICENSE_INFO_INTO_RELEASE.equals(action)) { writeSpdxLicenseInfoIntoRelease(request, response); + } else if (PortalConstants.PREPARE_IMPORT_BOM.equals(action)) { + prepareImportBom(request, response); } else if (PortalConstants.IMPORT_BOM.equals(action)) { importBom(request, response); } else if (PortalConstants.LICENSE_TO_SOURCE_FILE.equals(action)) { serveLicenseToSourceFileMapping(request, response); + } else if (PortalConstants.IMPORT_BOM_AS_NEW.equals(action)) { + importBomAsNew(request, response); } else if (isGenericAction(action)) { dealWithGenericAction(request, response, action); } else if (PortalConstants.LOAD_CHANGE_LOGS.equals(action) || PortalConstants.VIEW_CHANGE_LOGS.equals(action)) { @@ -241,8 +259,55 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th JSONObject dataForChangeLogs = changeLogsPortletUtilsPortletUtils.serveResourceForChangeLogs(request, response, action); writeJSON(request, response, dataForChangeLogs); - } else if (PortalConstants.EVALUATE_CLI_ATTACHMENTS.equals(action)) { - evaluateCLIAttachments(request, response); + } else if (action.equals("export-spdx")) { + exportSPDX(request, response); + } else if (action.equals("download-export-spdx")) { + downloadSPDX(request, response); + } + } + + private void downloadSPDX(ResourceRequest request, ResourceResponse response) { + final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + String releaseId = request.getParameter(PortalConstants.RELEASE_ID); + String outputFormat = request.getParameter(PortalConstants.WHAT); + User user = UserCacheHolder.getUserFromRequest(request); + String filename = releaseId + "." + outputFormat.toLowerCase(); + String exportFileName = null; + + if (PortalConstants.ACTION_CANCEL.equals(request.getParameter(PortalConstants.ACTION_CANCEL))) { + deleteFileExport(outputFormat, releaseId, filename); + return; + } + + try { + log.info("Download SPDX file"); + exportFileName = componentClient.getReleaseById(releaseId, user).getName().replaceAll("[\\/:*?\"<>|\\s]", "_") + + "_" + componentClient.getReleaseById(releaseId, user).getVersion().replaceAll("[\\/:*?\"<>|\\s]", "_") + + "_" + SW360Utils.getCreatedOn() + "." + outputFormat.toLowerCase(); + InputStream inputStream = new FileInputStream(filename); + PortletResponseUtil.sendFile(request, response, exportFileName, inputStream, CONTENT_TYPE_OPENXML_SPREADSHEET); + log.info("Download SPDX file success !!!"); + } catch (IOException | TException e) { + e.printStackTrace(); + } + deleteFileExport(outputFormat, releaseId, filename); + } + + // delete file after user download + private void deleteFileExport(String outputFormat, String releaseId, String filename) { + try { + if (!outputFormat.equals("JSON")) { + Files.delete(Paths.get(releaseId + ".json")); + } + if (outputFormat.equals("SPDX")) { + Files.delete(Paths.get("tmp.rdf")); + } + if (Files.exists(Paths.get(filename))) { + Files.delete(Paths.get(filename)); + } + } catch (IOException e) { + e.printStackTrace(); + log.error("Failed to delete files."); } } @@ -319,13 +384,28 @@ private void evaluateCLIAttachments(ResourceRequest request, ResourceResponse re writeJSON(request, response, jsonObject); } + private void exportSPDX(ResourceRequest request, ResourceResponse response) { + final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + String releaseId = request.getParameter(PortalConstants.RELEASE_ID); + String outputFormat = request.getParameter(PortalConstants.WHAT); + User user = UserCacheHolder.getUserFromRequest(request); + + try { + final RequestSummary requestSummary = componentClient.exportSPDX(user, releaseId, outputFormat); + renderRequestSummary(request, response, requestSummary); + } catch (TException e) { + log.error("Failed to export SPDX file.", e); + } + } + private void importBom(ResourceRequest request, ResourceResponse response) { final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); User user = UserCacheHolder.getUserFromRequest(request); String attachmentContentId = request.getParameter(ATTACHMENT_CONTENT_ID); + String rdfFilePath = request.getParameter(RDF_FILE_PATH); try { - final RequestSummary requestSummary = componentClient.importBomFromAttachmentContent(user, attachmentContentId); + final RequestSummary requestSummary = componentClient.importBomFromAttachmentContent(user, attachmentContentId, null, null, rdfFilePath); LiferayPortletURL releaseUrl = createDetailLinkTemplate(request); releaseUrl.setParameter(PortalConstants.PAGENAME, PortalConstants.PAGENAME_RELEASE_DETAIL); @@ -340,6 +420,43 @@ private void importBom(ResourceRequest request, ResourceResponse response) { } } + private void importBomAsNew(ResourceRequest request, ResourceResponse response) { + final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + User user = UserCacheHolder.getUserFromRequest(request); + String attachmentContentId = request.getParameter(ATTACHMENT_CONTENT_ID); + String newReleaseVersion = request.getParameter(NEW_RELEASE_VERSION); + String rdfFilePath = request.getParameter(RDF_FILE_PATH); + + try { + final RequestSummary requestSummary = componentClient.importBomFromAttachmentContent(user, attachmentContentId, newReleaseVersion, null, rdfFilePath); + + LiferayPortletURL releaseUrl = createDetailLinkTemplate(request); + releaseUrl.setParameter(PortalConstants.PAGENAME, PortalConstants.PAGENAME_RELEASE_DETAIL); + releaseUrl.setParameter(RELEASE_ID, requestSummary.getMessage()); + JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); + jsonObject.put("redirectUrl", releaseUrl.toString()); + + renderRequestSummary(request, response, requestSummary, jsonObject); + } catch (TException e) { + log.error("Failed to import BOM.", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + } + } + + private void prepareImportBom(ResourceRequest request, ResourceResponse response) { + final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + User user = UserCacheHolder.getUserFromRequest(request); + String attachmentContentId = request.getParameter(ATTACHMENT_CONTENT_ID); + + try { + final ImportBomRequestPreparation importBomRequestPreparation = componentClient.prepareImportBom(user, attachmentContentId); + renderRequestPreparation(request, response, importBomRequestPreparation); + } catch (TException e) { + log.error("Failed to import BOM.", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + } + } + @Override protected void dealWithFossologyAction(ResourceRequest request, ResourceResponse response, String action) throws IOException, PortletException { @@ -449,7 +566,7 @@ private void serveCheckComponentName(ResourceRequest request, ResourceResponse r } private void respondSimilarComponentsResponseJson(ResourceRequest request, ResourceResponse response, - List similarComponents, List errors) throws IOException { + List similarComponents, List errors) throws IOException { response.setContentType(ContentTypes.APPLICATION_JSON); JsonGenerator jsonGenerator = JSON_FACTORY.createGenerator(response.getWriter()); @@ -725,19 +842,25 @@ private void loadSpdxLicenseInfo(ResourceRequest request, ResourceResponse respo JsonGenerator jsonGenerator = JSON_FACTORY.createGenerator(response.getWriter()); jsonGenerator.writeStartObject(); if (concludedLicenseIds.size() > 0) { - jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle,"concluded.license.ids")); + jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle, "concluded.license.ids")); jsonGenerator.writeArrayFieldStart(LICENSE_IDS); - concludedLicenseIds.forEach(licenseId -> wrapException(() -> { jsonGenerator.writeString(licenseId); })); + concludedLicenseIds.forEach(licenseId -> wrapException(() -> { + jsonGenerator.writeString(licenseId); + })); jsonGenerator.writeEndArray(); } else if (CommonUtils.isNotEmpty(mainLicenseNames)) { - jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle,"main.license.id")); + jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle, "main.license.id")); jsonGenerator.writeArrayFieldStart(LICENSE_IDS); - mainLicenseNames.forEach(licenseId -> wrapException(() -> { jsonGenerator.writeString(licenseId); })); + mainLicenseNames.forEach(licenseId -> wrapException(() -> { + jsonGenerator.writeString(licenseId); + })); jsonGenerator.writeEndArray(); } jsonGenerator.writeStringField("otherLicense", LanguageUtil.get(resourceBundle,"other.license.ids")); jsonGenerator.writeArrayFieldStart("otherLicenseIds"); - otherLicenseNames.forEach(licenseId -> wrapException(() -> { jsonGenerator.writeString(licenseId); })); + otherLicenseNames.forEach(licenseId -> wrapException(() -> { + jsonGenerator.writeString(licenseId); + })); jsonGenerator.writeEndArray(); if (AttachmentType.INITIAL_SCAN_REPORT.equals(attachmentType)) { jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle, "possible.main.license.ids")); @@ -761,6 +884,7 @@ private void loadSpdxLicenseInfo(ResourceRequest request, ResourceResponse respo private void writeSpdxLicenseInfoIntoRelease(ResourceRequest request, ResourceResponse response) { User user = UserCacheHolder.getUserFromRequest(request); String releaseId = request.getParameter(PortalConstants.RELEASE_ID); + String attachmentContentId = request.getParameter(PortalConstants.ATTACHMENT_ID); ComponentService.Iface componentClient = thriftClients.makeComponentClient(); RequestStatus result = null; @@ -788,6 +912,8 @@ private void writeSpdxLicenseInfoIntoRelease(ResourceRequest request, ResourceRe } } result = componentClient.updateRelease(release, user); + + componentClient.importBomFromAttachmentContent(user, attachmentContentId, null, releaseId, null); } catch (TException | IOException e) { log.error("Cannot write license info into release " + releaseId + ".", e); response.setProperty(ResourceResponse.HTTP_STATUS_CODE, "500"); @@ -884,7 +1010,7 @@ private void prepareComponentEdit(RenderRequest request) { PortletUtils.setCustomFieldsEdit(request, user, component); setUsingDocs(request, user, null, component.getReleaseIds()); setAttachmentsInRequest(request, component); - SessionMessages.add(request, "request_processed", LanguageUtil.get(resourceBundle,"new.component")); + SessionMessages.add(request, "request_processed", LanguageUtil.get(resourceBundle, "new.component")); } } } @@ -906,7 +1032,10 @@ private void prepareReleaseEdit(RenderRequest request, RenderResponse response) ComponentService.Iface client = thriftClients.makeComponentClient(); Component component; Release release; - + SPDXDocument spdxDocument = new SPDXDocument(); + DocumentCreationInformation documentCreationInfo = new DocumentCreationInformation(); + Set packageInfos = new HashSet<>(); + PackageInformation packageInfo = new PackageInformation(); if (!isNullOrEmpty(releaseId)) { release = client.getAccessibleReleaseByIdForEdit(releaseId, user); Map sortedAdditionalData = getSortedMap(release.getAdditionalData(), true); @@ -926,10 +1055,30 @@ private void prepareReleaseEdit(RenderRequest request, RenderResponse response) } component = client.getAccessibleComponentById(id, user); + String spdxDocumentId = release.getSpdxId(); + if (!isNullOrEmpty(spdxDocumentId)) { + SPDXDocumentService.Iface SPDXDocumentClient = thriftClients.makeSPDXClient(); + spdxDocument = SPDXDocumentClient.getSPDXDocumentForEdit(spdxDocumentId, user); + String spdxDocumentCreationInfoId = spdxDocument.getSpdxDocumentCreationInfoId(); + Set spdxPackageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + if (!isNullOrEmpty(spdxDocumentCreationInfoId)) { + DocumentCreationInformationService.Iface doClient = thriftClients.makeSPDXDocumentInfoClient(); + documentCreationInfo = doClient.getDocumentCreationInfoForEdit(spdxDocumentCreationInfoId, user); + } + if (spdxPackageInfoIds != null && !spdxPackageInfoIds.isEmpty()) { + PackageInformationService.Iface paClient = thriftClients.makeSPDXPackageInfoClient(); + for (String spdxPackageInfoId : spdxPackageInfoIds) { + packageInfo = paClient.getPackageInformationForEdit(spdxPackageInfoId, user); + packageInfos.add(packageInfo); + } + } + } + + } else { component = client.getAccessibleComponentById(id, user); release = (Release) request.getAttribute(RELEASE); - if(release == null) { + if (release == null) { release = new Release(); release.setComponentId(id); release.setClearingState(ClearingState.NEW_CLEARING); @@ -939,7 +1088,7 @@ private void prepareReleaseEdit(RenderRequest request, RenderResponse response) putDirectlyLinkedReleaseRelationsWithAccessibilityInRequest(request, release, user); setAttachmentsInRequest(request, release); setUsingDocs(request, null, user, client); - SessionMessages.add(request, "request_processed", LanguageUtil.get(resourceBundle,"new.license")); + SessionMessages.add(request, "request_processed", LanguageUtil.get(resourceBundle, "new.license")); } } @@ -963,7 +1112,41 @@ private void prepareReleaseEdit(RenderRequest request, RenderResponse response) request.setAttribute(COMPONENT, component); request.setAttribute(IS_USER_AT_LEAST_ECC_ADMIN, PermissionUtils.isUserAtLeast(UserGroup.ECC_ADMIN, user) || PermissionUtils.isUserAtLeastDesiredRoleInSecondaryGroup(UserGroup.ECC_ADMIN, allSecRoles) ? "Yes" : "No"); - + request.setAttribute(SPDXDOCUMENT, spdxDocument); + request.setAttribute(SPDX_DOCUMENT_CREATION_INFO, documentCreationInfo); + request.setAttribute(SPDX_PACKAGE_INFO, packageInfos); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + if (!spdxDocument.isSetId()) { + spdxDocument = generateSpdxDocument(); + } + String spdxDocumentJson = objectMapper.writeValueAsString(spdxDocument); + request.setAttribute("spdxDocumentJson", spdxDocumentJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + if (!documentCreationInfo.isSetId()) { + documentCreationInfo = generateDocumentCreationInformation(); + } + String documentCreationInfoJson = objectMapper.writeValueAsString(documentCreationInfo); + request.setAttribute("documentCreationInfoJson", documentCreationInfoJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + JSONArray packageArray = JSONFactoryUtil.createJSONArray(); + Set setPackage = new HashSet<>(); + for (PackageInformation pack : packageInfos) { + String packageInfoJson = objectMapper.writeValueAsString(pack); + setPackage.add(packageInfoJson); + packageArray.put(packageInfoJson); + } + request.setAttribute("packageInfoJson", setPackage); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } catch (TException e) { if (e instanceof SW360Exception) { SW360Exception sw360Exp = (SW360Exception)e; @@ -981,6 +1164,72 @@ private void prepareReleaseEdit(RenderRequest request, RenderResponse response) } } + private SPDXDocument generateSpdxDocument() { + SPDXDocument spdxDocument = new SPDXDocument(); + for (SPDXDocument._Fields field : SPDXDocument._Fields.values()) { + switch (SPDXDocument.metaDataMap.get(field).valueMetaData.type) { + case TType.SET: + spdxDocument.setFieldValue(field, new HashSet<>()); + break; + case TType.STRING: + spdxDocument.setFieldValue(field, ""); + break; + default: + break; + } + } + return spdxDocument; + } + + private DocumentCreationInformation generateDocumentCreationInformation() { + DocumentCreationInformation documentCreationInfo = new DocumentCreationInformation(); + for (DocumentCreationInformation._Fields field : DocumentCreationInformation._Fields.values()) { + switch (DocumentCreationInformation.metaDataMap.get(field).valueMetaData.type) { + case TType.SET: + documentCreationInfo.setFieldValue(field, new HashSet<>()); + break; + case TType.STRING: + documentCreationInfo.setFieldValue(field, ""); + break; + default: + break; + } + } + return documentCreationInfo; + } + + private PackageInformation generatePackageInfomation() { + PackageInformation packageInfo = new PackageInformation(); + + for (PackageInformation._Fields field : PackageInformation._Fields.values()) { + + switch (field) { + case PACKAGE_VERIFICATION_CODE: { + PackageVerificationCode packageVerificationCode = new PackageVerificationCode(); + packageInfo.setPackageVerificationCode(packageVerificationCode); + break; + } + default: { + this.field = field; + switch (PackageInformation.metaDataMap.get(field).valueMetaData.type) { + case TType.SET: + packageInfo.setFieldValue(field, new HashSet<>()); + break; + case TType.STRING: + packageInfo.setFieldValue(field, ""); + break; + case TType.BOOL: + packageInfo.setFieldValue(field, true); + default: + break; + } + break; + } + } + } + return packageInfo; + } + private void prepareReleaseDuplicate(RenderRequest request, RenderResponse response) throws PortletException { String id = request.getParameter(COMPONENT_ID); String releaseId = request.getParameter(RELEASE_ID); @@ -1114,7 +1363,7 @@ private void generateComponentMergeWizardStep0Response(ActionRequest request, Js jsonGenerator.writeStartObject(); jsonGenerator.writeArrayFieldStart("components"); - componentSummary.stream().filter( component -> !component.getId().equals(srcId)).forEach(component -> { + componentSummary.stream().filter(component -> !component.getId().equals(srcId)).forEach(component -> { try { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("id", component.getId()); @@ -1158,7 +1407,7 @@ private void generateComponentMergeWizardStep2Response(ActionRequest request, Js jsonGenerator.writeStartObject(); // adding common title - jsonGenerator.writeRaw("\""+ COMPONENT_SELECTION +"\":" + JSON_THRIFT_SERIALIZER.toString(componentSelection) + ","); + jsonGenerator.writeRaw("\"" + COMPONENT_SELECTION + "\":" + JSON_THRIFT_SERIALIZER.toString(componentSelection) + ","); jsonGenerator.writeStringField(COMPONENT_SOURCE_ID, componentSourceId); jsonGenerator.writeEndObject(); @@ -1184,7 +1433,7 @@ private void generateComponentMergeWizardStep3Response(ActionRequest request, Js // write response JSON jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("redirectUrl", componentUrl.toString()); - if (status == RequestStatus.IN_USE){ + if (status == RequestStatus.IN_USE) { jsonGenerator.writeStringField("error", "Cannot merge when one of the components has an active moderation request."); } else if (status == RequestStatus.ACCESS_DENIED) { jsonGenerator.writeStringField("error", "You do not have sufficient permissions."); @@ -1292,11 +1541,11 @@ private void generateReleaseMergeWizardStep0Response(ActionRequest request, Json ComponentService.Iface cClient = thriftClients.makeComponentClient(); List releases = cClient.getReleasesByComponentId(componentId, sessionUser); - + jsonGenerator.writeStartObject(); jsonGenerator.writeArrayFieldStart("releases"); - releases.stream().filter( release -> !release.getId().equals(targetId) ).forEach(release -> { + releases.stream().filter(release -> !release.getId().equals(targetId)).forEach(release -> { try { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("id", release.getId()); @@ -1326,15 +1575,15 @@ private void generateReleaseMergeWizardStep1Response(ActionRequest request, Json boolean matchingPair = false; boolean foundSourceAttachments = false; Set attachmentHashes = new HashSet<>(); - for(Attachment attachment : nullToEmptySet(releaseTarget.getAttachments())) { - if(attachment.getAttachmentType().equals(AttachmentType.SOURCE) || attachment.getAttachmentType().equals(AttachmentType.SOURCE_SELF)) { + for (Attachment attachment : nullToEmptySet(releaseTarget.getAttachments())) { + if (attachment.getAttachmentType().equals(AttachmentType.SOURCE) || attachment.getAttachmentType().equals(AttachmentType.SOURCE_SELF)) { attachmentHashes.add(attachment.getSha1()); foundSourceAttachments = true; } } - for(Attachment attachment : nullToEmptySet(releaseSource.getAttachments())) { - if(attachment.getAttachmentType().equals(AttachmentType.SOURCE) || attachment.getAttachmentType().equals(AttachmentType.SOURCE_SELF)) { - if(attachmentHashes.contains(attachment.getSha1())) { + for (Attachment attachment : nullToEmptySet(releaseSource.getAttachments())) { + if (attachment.getAttachmentType().equals(AttachmentType.SOURCE) || attachment.getAttachmentType().equals(AttachmentType.SOURCE_SELF)) { + if (attachmentHashes.contains(attachment.getSha1())) { matchingPair = true; break; } @@ -1342,7 +1591,7 @@ private void generateReleaseMergeWizardStep1Response(ActionRequest request, Json } } - if(foundSourceAttachments && !matchingPair) { + if (foundSourceAttachments && !matchingPair) { jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("error", "Both releases must have at least one pair of same source attachments or no source attachments at all. Otherwise a merge is not possible."); jsonGenerator.writeEndObject(); @@ -1350,17 +1599,17 @@ private void generateReleaseMergeWizardStep1Response(ActionRequest request, Json } Map> displayInformation = new HashMap<>(); - + addToMap(displayInformation, "mainlineState", releaseTarget.getMainlineState()); addToMap(displayInformation, "mainlineState", releaseSource.getMainlineState()); addToMap(displayInformation, "repositorytype", releaseTarget.getRepository() != null ? releaseTarget.getRepository().getRepositorytype() : null); addToMap(displayInformation, "repositorytype", releaseSource.getRepository() != null ? releaseSource.getRepository().getRepositorytype() : null); addToMap(displayInformation, "eccStatus", releaseTarget.getEccInformation().getEccStatus()); addToMap(displayInformation, "eccStatus", releaseSource.getEccInformation().getEccStatus()); - for(Attachment attachment : nullToEmptySet(releaseSource.getAttachments())) { + for (Attachment attachment : nullToEmptySet(releaseSource.getAttachments())) { addToMap(displayInformation, "attachmentType", attachment.getAttachmentType()); } - for(Attachment attachment : nullToEmptySet(releaseTarget.getAttachments())) { + for (Attachment attachment : nullToEmptySet(releaseTarget.getAttachments())) { addToMap(displayInformation, "attachmentType", attachment.getAttachmentType()); } @@ -1369,11 +1618,11 @@ private void generateReleaseMergeWizardStep1Response(ActionRequest request, Json releaseIds.addAll(nullToEmptyMap(releaseTarget.getReleaseIdToRelationship()).keySet()); List releases = cClient.getReleasesById(releaseIds, sessionUser); Map releaseToNameMap = new HashMap(); - for(Release release : releases) { + for (Release release : releases) { releaseToNameMap.put(release.getId(), release.getName() + " (" + release.getVersion() + ")"); } displayInformation.put("release", releaseToNameMap); - + jsonGenerator.writeStartObject(); // adding common title @@ -1387,7 +1636,7 @@ private void generateReleaseMergeWizardStep1Response(ActionRequest request, Json private void addToMap(Map> map, String key, TEnum value) { Map subMap = map.getOrDefault(key, new HashMap()); - if(value != null) { + if (value != null) { subMap.put(value.getValue() + "", ThriftEnumUtils.enumToString(value)); } map.put(key, subMap); @@ -1413,7 +1662,7 @@ private Map getUsageInformationForReleaseMerge(String releaseSo usageInformation.put("releaseVulnerabilities", releaseVulnerabilities.size()); List projectRatings = vulnerabilityClient.getProjectVulnerabilityRatingsByReleaseId(releaseSourceId, sessionUser); usageInformation.put("projectRatings", projectRatings.size()); - + return usageInformation; } @@ -1427,7 +1676,7 @@ private void generateReleaseMergeWizardStep2Response(ActionRequest request, Json jsonGenerator.writeStartObject(); // adding common title - jsonGenerator.writeRaw("\""+ RELEASE_SELECTION +"\":" + JSON_THRIFT_SERIALIZER.toString(releaseSelection) + ","); + jsonGenerator.writeRaw("\"" + RELEASE_SELECTION + "\":" + JSON_THRIFT_SERIALIZER.toString(releaseSelection) + ","); jsonGenerator.writeStringField(RELEASE_SOURCE_ID, releaseSourceId); jsonGenerator.writeEndObject(); @@ -1454,7 +1703,7 @@ private void generateReleaseMergeWizardStep3Response(ActionRequest request, Json // write response JSON jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("redirectUrl", releaseUrl.toString()); - if (status == RequestStatus.IN_USE){ + if (status == RequestStatus.IN_USE) { jsonGenerator.writeStringField("error", "Cannot merge when one of the releases has an active moderation request."); } else if (status == RequestStatus.ACCESS_DENIED) { jsonGenerator.writeStringField("error", "You do not have sufficient permissions."); @@ -1592,7 +1841,7 @@ private void prepareReleaseDetailView(RenderRequest request, RenderResponse resp } Map permissions = release.getPermissions(); - + request.setAttribute(PortalConstants.WRITE_ACCESS_USER, permissions.get(RequestedAction.WRITE)); if (isNullOrEmpty(id)) { id = release.getComponentId(); @@ -1613,6 +1862,61 @@ private void prepareReleaseDetailView(RenderRequest request, RenderResponse resp if (release != null) { addReleaseBreadcrumb(request, response, release); } + String spdxDocumentId = release.getSpdxId(); + SPDXDocument spdxDocument = new SPDXDocument(); + DocumentCreationInformation documentCreationInfo = new DocumentCreationInformation(); + PackageInformation packageInfo = new PackageInformation(); + Set packageInfos = new HashSet<>(); + if (!isNullOrEmpty(spdxDocumentId)) { + SPDXDocumentService.Iface SPDXDocumentClient = thriftClients.makeSPDXClient(); + spdxDocument = SPDXDocumentClient.getSPDXDocumentById(spdxDocumentId, user); + String spdxDocumentCreationInfoId = spdxDocument.getSpdxDocumentCreationInfoId(); + Set spdxPackageInfoIds = spdxDocument.getSpdxPackageInfoIds(); + if (!isNullOrEmpty(spdxDocumentCreationInfoId)) { + DocumentCreationInformationService.Iface doClient = thriftClients.makeSPDXDocumentInfoClient(); + documentCreationInfo = doClient.getDocumentCreationInformationById(spdxDocumentCreationInfoId, user); + } + if (spdxPackageInfoIds != null) { + PackageInformationService.Iface paClient = thriftClients.makeSPDXPackageInfoClient(); + for (String spdxPackageInfoId : spdxPackageInfoIds) { + packageInfo = paClient.getPackageInformationById(spdxPackageInfoId, user); + packageInfos.add(packageInfo); + } + } + request.setAttribute(SPDXDOCUMENT, spdxDocument); + request.setAttribute(SPDX_DOCUMENT_CREATION_INFO, documentCreationInfo); + request.setAttribute(SPDX_PACKAGE_INFO, packageInfos); + } + + ObjectMapper objectMapper = new ObjectMapper(); + try { + if (!spdxDocument.isSetId()) { + spdxDocument = generateSpdxDocument(); + } + String spdxDocumentJson = objectMapper.writeValueAsString(spdxDocument); + request.setAttribute("spdxDocumentJson", spdxDocumentJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + if (!documentCreationInfo.isSetId()) { + documentCreationInfo = generateDocumentCreationInformation(); + } + String documentCreationInfoJson = objectMapper.writeValueAsString(documentCreationInfo); + request.setAttribute("documentCreationInfoJson", documentCreationInfoJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + Set setPackage = new HashSet<>(); + for (PackageInformation pack : packageInfos) { + String packageInfoJson = objectMapper.writeValueAsString(pack); + setPackage.add(packageInfoJson); + } + request.setAttribute("packageInfoJson", setPackage); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } } catch (TException e) { if (e instanceof SW360Exception) { @@ -1632,7 +1936,7 @@ private void prepareReleaseDetailView(RenderRequest request, RenderResponse resp } private String createFossologyJobViewLink(ExternalToolProcessStep processStep, - Map> configKeyToValues, String fossologyJobsViewLink) { + Map> configKeyToValues, String fossologyJobsViewLink) { String uploadId = null; if (processStep != null) { uploadId = processStep.getResult(); @@ -1646,7 +1950,7 @@ private String createFossologyJobViewLink(ExternalToolProcessStep processStep, URI fossologyRestURI = new URI(url); fossologyHostName = fossologyRestURI.getHost(); fossologyPath = fossologyRestURI.getPath(); - fossologyPath = fossologyPath.substring(0,fossologyPath.indexOf("/api/v")); + fossologyPath = fossologyPath.substring(0, fossologyPath.indexOf("/api/v")); protocol = fossologyRestURI.getScheme(); int port = fossologyRestURI.getPort(); portStr = port == -1 ? StringUtils.EMPTY : ":" + port; @@ -1680,7 +1984,7 @@ private void setSpdxAttachmentsInRequest(RenderRequest request, Release release) request.setAttribute(PortalConstants.SPDX_ATTACHMENTS, spdxAttachments); } - private String formatedMessageForVul(List infoHistory){ + private String formatedMessageForVul(List infoHistory) { return CommonVulnerabilityPortletUtils.formatedMessageForVul(infoHistory, e -> e.getVerificationState().name(), e -> e.getCheckedOn(), @@ -1701,7 +2005,7 @@ private void putVulnerabilitiesInRequestRelease(RenderRequest request, String re putVulnerabilitiesInRequest(request, vuls, user); } - private void putVulnerabilitiesInRequestComponent(RenderRequest request, String componentId, User user, boolean isVulEditable) throws TException{ + private void putVulnerabilitiesInRequestComponent(RenderRequest request, String componentId, User user, boolean isVulEditable) throws TException { VulnerabilityService.Iface vulClient = thriftClients.makeVulnerabilityClient(); List vuls; if (isVulEditable) { @@ -1721,14 +2025,14 @@ private void putVulnerabilitiesInRequest(RenderRequest request, List> vulnerabilityVerifications, Map> vulnerabilityTooltips, - VulnerabilityDTO vulnerability){ + VulnerabilityDTO vulnerability) { String vulnerabilityId = vulnerability.getExternalId(); String releaseId = vulnerability.getIntReleaseId(); Map vulnerabilityVerification = vulnerabilityVerifications.computeIfAbsent(vulnerabilityId, k -> new HashMap<>()); Map vulnerabilityTooltip = vulnerabilityTooltips.computeIfAbsent(vulnerabilityId, k -> new HashMap<>()); ReleaseVulnerabilityRelation relation = vulnerability.getReleaseVulnerabilityRelation(); - if (! relation.isSetVerificationStateInfo()) { + if (!relation.isSetVerificationStateInfo()) { vulnerabilityVerification.put(releaseId, VerificationState.NOT_CHECKED); vulnerabilityTooltip.put(releaseId, "Not checked yet."); } else { @@ -1747,7 +2051,7 @@ private void putVulnerabilityMetadatasInRequest(RenderRequest request, List ! VerificationState.INCORRECT.equals(getVerificationState(vul))) + .filter(vul -> !VerificationState.INCORRECT.equals(getVerificationState(vul))) .map(VulnerabilityDTO::getExternalId) .collect(Collectors.toSet()) .size(); @@ -1765,8 +2069,8 @@ private void putVulnerabilityMetadatasInRequest(RenderRequest request, List> getComponentFilterMap(PortletRequest request) { String query = new StringBuilder("[%s ").append(PortalConstants.TO).append(" %s]").toString(); DateRange range = ThriftEnumUtils.stringToEnum(dateRange, DateRange.class); switch (range) { - case EQUAL: - break; - case LESS_THAN_OR_EQUAL_TO: - parameter = String.format(query, PortalConstants.EPOCH_DATE, parameter); - break; - case GREATER_THAN_OR_EQUAL_TO: - parameter = String.format(query, parameter, upperLimit); - break; - case BETWEEN: - String endDate = request.getParameter(PortalConstants.END_DATE); - if (isNullEmptyOrWhitespace(endDate)) { - endDate = upperLimit; - } - parameter = String.format(query, parameter, endDate); - break; + case EQUAL: + break; + case LESS_THAN_OR_EQUAL_TO: + parameter = String.format(query, PortalConstants.EPOCH_DATE, parameter); + break; + case GREATER_THAN_OR_EQUAL_TO: + parameter = String.format(query, parameter, upperLimit); + break; + case BETWEEN: + String endDate = request.getParameter(PortalConstants.END_DATE); + if (isNullEmptyOrWhitespace(endDate)) { + endDate = upperLimit; + } + parameter = String.format(query, parameter, endDate); + break; } } Set values = CommonUtils.splitToSet(parameter); @@ -1925,7 +2229,7 @@ public void updateComponent(ActionRequest request, ActionResponse response) thro setSessionMessage(request, requestStatus, "Component", "update", component.getName()); if (RequestStatus.DUPLICATE.equals(requestStatus) || RequestStatus.DUPLICATE_ATTACHMENT.equals(requestStatus) || RequestStatus.NAMINGERROR.equals(requestStatus)) { - if(RequestStatus.DUPLICATE.equals(requestStatus)) + if (RequestStatus.DUPLICATE.equals(requestStatus)) setSW360SessionError(request, ErrorMessages.COMPONENT_DUPLICATE); else if (RequestStatus.NAMINGERROR.equals(requestStatus)) setSW360SessionError(request, ErrorMessages.COMPONENT_NAMING_ERROR); @@ -1949,7 +2253,7 @@ else if (RequestStatus.NAMINGERROR.equals(requestStatus)) AddDocumentRequestSummary summary = client.addComponent(component, user); AddDocumentRequestStatus status = summary.getRequestStatus(); - switch(status){ + switch (status) { case SUCCESS: String successMsg = "Component " + component.getName() + " added successfully"; SessionMessages.add(request, "request_processed", successMsg); @@ -2018,7 +2322,7 @@ public void updateRelease(ActionRequest request, ActionResponse response) throws setSessionMessage(request, requestStatus, "Release", "update", printName(release)); if (RequestStatus.DUPLICATE.equals(requestStatus) || RequestStatus.DUPLICATE_ATTACHMENT.equals(requestStatus) || RequestStatus.NAMINGERROR.equals(requestStatus)) { - if(RequestStatus.DUPLICATE.equals(requestStatus)) + if (RequestStatus.DUPLICATE.equals(requestStatus)) setSW360SessionError(request, ErrorMessages.RELEASE_DUPLICATE); else if (RequestStatus.NAMINGERROR.equals(requestStatus)) setSW360SessionError(request, ErrorMessages.RELEASE_NAME_VERSION_ERROR); @@ -2047,6 +2351,7 @@ else if (RequestStatus.NAMINGERROR.equals(requestStatus)) request.setAttribute(WebKeys.REDIRECT, redirectUrl.toString()); sendRedirect(request, response); + SpdxPortlet.updateSPDX(request, response, user, releaseId, false); } } else { release = new Release(); @@ -2066,8 +2371,29 @@ else if (RequestStatus.NAMINGERROR.equals(requestStatus)) AddDocumentRequestSummary summary = client.addRelease(release, user); AddDocumentRequestStatus status = summary.getRequestStatus(); - switch(status){ + switch (status) { case SUCCESS: + ObjectMapper objectMapper = new ObjectMapper(); + try { + String spdxDocumentJson = objectMapper.writeValueAsString(generateSpdxDocument()); + request.setAttribute(SPDXDocument._Fields.TYPE.toString(), spdxDocumentJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + String documentCreationInfoJson = objectMapper.writeValueAsString(generateDocumentCreationInformation()); + request.setAttribute(SPDXDocument._Fields.SPDX_DOCUMENT_CREATION_INFO_ID.toString(), documentCreationInfoJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + try { + String packageInfoJson = objectMapper.writeValueAsString(generatePackageInfomation()); + packageInfoJson = "[" + packageInfoJson + "]"; + request.setAttribute(SPDXDocument._Fields.SPDX_PACKAGE_INFO_IDS.toString(), packageInfoJson); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + SpdxPortlet.updateSPDX(request, response, user, summary.getId(), true); response.setRenderParameter(RELEASE_ID, summary.getId()); String successMsg = "Release " + printName(release) + " added successfully"; SessionMessages.add(request, "request_processed", successMsg); @@ -2107,7 +2433,7 @@ private void prepareRequestForReleaseEditAfterDuplicateError(ActionRequest reque } private void fillVendor(Release release) throws TException { - if(!isNullOrEmpty(release.getVendorId()) && release.isSetVendorId()) { + if (!isNullOrEmpty(release.getVendorId()) && release.isSetVendorId()) { VendorService.Iface client = thriftClients.makeVendorClient(); Vendor vendor = client.getByID(release.getVendorId()); release.setVendor(vendor); @@ -2154,7 +2480,7 @@ private void updateVulnerabilitiesRelease(ResourceRequest request, ResourceRespo JSONObject responseData = PortletUtils.importStatusToJSON(importStatus); PrintWriter writer = response.getWriter(); writer.write(responseData.toString()); - } catch (TException e){ + } catch (TException e) { log.error("Error updating CVEs for release in backend.", e); } } diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/spdx/SpdxPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/spdx/SpdxPortlet.java new file mode 100644 index 0000000000..2298fcd85d --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/spdx/SpdxPortlet.java @@ -0,0 +1,415 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.eclipse.sw360.portal.portlets.components.spdx; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.liferay.portal.kernel.json.JSONArray; +import com.liferay.portal.kernel.json.JSONException; +import com.liferay.portal.kernel.json.JSONFactoryUtil; +import com.liferay.portal.kernel.json.JSONObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.thrift.TException; +import org.eclipse.sw360.datahandler.thrift.ThriftClients; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetRange; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocumentService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformationService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Strings.isNullOrEmpty; + +public abstract class SpdxPortlet { + + private SpdxPortlet() { + // Utility class with only static functions + } + + private static final Logger log = LogManager.getLogger(SpdxPortlet.class); + private static final ObjectMapper mapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private static SPDXDocument parseSPDXDocumentFromRequest(String jsonData) { + SPDXDocument spdx = new SPDXDocument(); + if (jsonData == null) { + return null; + } + try { + JSONObject json = JSONFactoryUtil.createJSONObject(jsonData); + Set snippets = parseSnippets(json); + json.remove("snippets"); + Set relationships = parseRelationships(json); + json.remove("relationships"); + Set annotations = parseAnnotations(json); + json.remove("annotations"); + Set licensingInfo = parseLicensingInfo(json); + json.remove("otherLicensingInformationDetecteds"); + json.remove("documentState"); + json.remove("permissions"); + try { + spdx = mapper.readValue(json.toJSONString(), SPDXDocument.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + spdx.setSnippets(snippets); + spdx.setRelationships(relationships); + spdx.setAnnotations(annotations); + spdx.setOtherLicensingInformationDetecteds(licensingInfo); + } catch (JSONException e) { + e.printStackTrace(); + } + return spdx; + } + + private static DocumentCreationInformation parseDocumentCreationInfoFromRequest(String jsonData) { + DocumentCreationInformation documentCreationInfo = new DocumentCreationInformation(); + if (jsonData == null) { + return null; + } + try { + JSONObject json = JSONFactoryUtil.createJSONObject(jsonData); + Set externalDocumentRefs = parseExternalDocumentReferences(json); + json.remove("externalDocumentRefs"); + Set creator = parseCreator(json); + json.remove("creator"); + json.remove("documentState"); + json.remove("permissions"); + try { + documentCreationInfo = mapper.readValue(json.toJSONString(), DocumentCreationInformation.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + documentCreationInfo.setExternalDocumentRefs(externalDocumentRefs); + documentCreationInfo.setCreator(creator); + } catch (JSONException e) { + e.printStackTrace(); + } + return documentCreationInfo; + } + + private static PackageInformation parsePackageInfoFromRequest(String jsonData) { + PackageInformation packageInfo = new PackageInformation(); + if (jsonData == null) { + return null; + } + try { + JSONObject json = JSONFactoryUtil.createJSONObject(jsonData); + PackageVerificationCode packageVerificationCode = parsePackageVerificationCode(json); + json.remove("packageVerificationCode"); + Set checksums = parseChecksum(json); + json.remove("checksums"); + Set externalRefs = parseExternalReference(json); + json.remove("externalReferences"); + Set annotations = parseAnnotations(json); + json.remove("annotations"); + json.remove("documentState"); + json.remove("permissions"); + try { + packageInfo = mapper.readValue(json.toJSONString(), PackageInformation.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + packageInfo.setPackageVerificationCode(packageVerificationCode); + packageInfo.setChecksums(checksums); + packageInfo.setExternalRefs(externalRefs); + packageInfo.setAnnotations(annotations); + } catch (JSONException e) { + e.printStackTrace(); + } + return packageInfo; + } + + private static Set parsePackageInfosFromRequest(String jsonData) { + Set packageInfos = new HashSet<>(); + if (jsonData == null) { + return null; + } + try { + JSONArray arrayPackages = JSONFactoryUtil.createJSONArray(jsonData); + if (arrayPackages == null) { + return packageInfos; + } + for (int i = 0; i < arrayPackages.length(); i++) { + PackageInformation packageInfo = parsePackageInfoFromRequest(arrayPackages.getJSONObject(i).toJSONString()); + if (packageInfo != null) { + packageInfos.add(packageInfo); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + return packageInfos; + } + + public static void updateSPDX(ActionRequest request, ActionResponse response, User user, String releaseId, boolean addNew) throws TException { + String spdxDocumentData; + String documentCreationInfoData; + String packageInfoData; + String spdxDocumentId = ""; + + if (addNew) { + spdxDocumentData = (String) request.getAttribute(SPDXDocument._Fields.TYPE.toString()); + documentCreationInfoData = (String) request.getAttribute(SPDXDocument._Fields.SPDX_DOCUMENT_CREATION_INFO_ID.toString()); + packageInfoData = (String) request.getAttribute(SPDXDocument._Fields.SPDX_PACKAGE_INFO_IDS.toString()); + } else { + spdxDocumentData = request.getParameter(SPDXDocument._Fields.TYPE.toString()); + documentCreationInfoData = request.getParameter(SPDXDocument._Fields.SPDX_DOCUMENT_CREATION_INFO_ID.toString()); + packageInfoData = request.getParameter(SPDXDocument._Fields.SPDX_PACKAGE_INFO_IDS.toString()); + } + if (!isNullOrEmpty(spdxDocumentData)) { + SPDXDocument spdx = parseSPDXDocumentFromRequest(spdxDocumentData); + SPDXDocumentService.Iface spdxClient = new ThriftClients().makeSPDXClient(); + if (spdx != null) { + if (isNullOrEmpty(spdx.getReleaseId()) && !isNullOrEmpty(releaseId)) { + spdx.setReleaseId(releaseId); + } + if (isNullOrEmpty(spdx.getId())) { + spdx.unsetId(); + spdx.unsetRevision(); + spdxDocumentId = spdxClient.addSPDXDocument(spdx, user).getId(); + } else { + spdxClient.updateSPDXDocument(spdx, user); + spdxDocumentId = spdx.getId(); + } + } + } + if (!isNullOrEmpty(documentCreationInfoData)) { + DocumentCreationInformation document = parseDocumentCreationInfoFromRequest(documentCreationInfoData); + if (document != null) { + DocumentCreationInformationService.Iface documentClient = new ThriftClients().makeSPDXDocumentInfoClient(); + if (isNullOrEmpty(document.getSpdxDocumentId())) { + document.setSpdxDocumentId(spdxDocumentId); + } + if (isNullOrEmpty(document.getId())) { + document.unsetId(); + document.unsetRevision(); + documentClient.addDocumentCreationInformation(document, user); + } else { + documentClient.updateDocumentCreationInformation(document, user); + } + } + } + if (!isNullOrEmpty(packageInfoData)) { + Set packageInfos = parsePackageInfosFromRequest(packageInfoData); + SPDXDocumentService.Iface SPDXClient = new ThriftClients().makeSPDXClient(); + SPDXDocument spdxDocument = SPDXClient.getSPDXDocumentById(spdxDocumentId, user); + idDeletePackageInfo(packageInfos, spdxDocument, user); + if (packageInfos != null) { + PackageInformationService.Iface packageClient = new ThriftClients().makeSPDXPackageInfoClient(); + for (PackageInformation packageInfo : packageInfos) { + if (isNullOrEmpty(packageInfo.getSpdxDocumentId())) { + packageInfo.setSpdxDocumentId(spdxDocumentId); + } + if (isNullOrEmpty(packageInfo.getId())) { + packageInfo.unsetId(); + packageInfo.unsetRevision(); + packageClient.addPackageInformation(packageInfo, user); + } else { + packageClient.updatePackageInformation(packageInfo, user); + } + } + } + } + } + + private static void idDeletePackageInfo(Set packageInfos, SPDXDocument spdxDocument, User user) { + Set spdxDocumentId = spdxDocument.getSpdxPackageInfoIds(); + Set listIdPackageInfos = new HashSet<>(); + packageInfos.forEach(pInfo -> listIdPackageInfos.add(pInfo.getId())); + for (String s : spdxDocumentId) { + if (!listIdPackageInfos.contains(s)) { + PackageInformationService.Iface packageClient = new ThriftClients().makeSPDXPackageInfoClient(); + try { + packageClient.deletePackageInformation(s, user); + } catch (Exception e) { + log.error("Could not delete SDPX Package Info {}", e.getMessage()); + } + } + } + } + + private static Set parseSnippets(JSONObject json) { + Set snippets = new HashSet<>(); + JSONArray arraySnippets = json.getJSONArray("snippets"); + if (arraySnippets == null) { + return snippets; + } + for (int i = 0; i < arraySnippets.length(); i++) { + try { + JSONObject objectSnippet = arraySnippets.getJSONObject(i); + JSONArray arraySnippet = objectSnippet.getJSONArray("snippetRanges"); + objectSnippet.remove("snippetRanges"); + SnippetInformation snippet = mapper.readValue(objectSnippet.toJSONString(), SnippetInformation.class); + Set snippetRanges = new HashSet<>(); + for (int j = 0; j < arraySnippet.length(); j++) { + snippetRanges.add(mapper.readValue(arraySnippet.getString(j), SnippetRange.class)); + } + snippet.setSnippetRanges(snippetRanges); + snippets.add(snippet); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return snippets; + } + + private static Set parseRelationships(JSONObject json) { + Set relationships = new HashSet<>(); + JSONArray arrayRelationships = json.getJSONArray("relationships"); + if (arrayRelationships == null) { + return relationships; + } + for (int i = 0; i < arrayRelationships.length(); i++) { + try { + relationships + .add(mapper.readValue(arrayRelationships.getString(i), RelationshipsBetweenSPDXElements.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return relationships; + } + + private static Set parseAnnotations(JSONObject json) { + Set annotations = new HashSet<>(); + JSONArray arrayAnnotations = json.getJSONArray("annotations"); + if (arrayAnnotations == null) { + return annotations; + } + for (int i = 0; i < arrayAnnotations.length(); i++) { + try { + annotations.add(mapper.readValue(arrayAnnotations.getString(i), Annotations.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return annotations; + } + + private static Set parseLicensingInfo(JSONObject json) { + Set licensingInfo = new HashSet<>(); + JSONArray arrayLicensingInfo = json.getJSONArray("otherLicensingInformationDetecteds"); + if (arrayLicensingInfo == null) { + return licensingInfo; + } + for (int i = 0; i < arrayLicensingInfo.length(); i++) { + try { + licensingInfo.add( + mapper.readValue(arrayLicensingInfo.getString(i), OtherLicensingInformationDetected.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return licensingInfo; + } + + private static Set parseExternalDocumentReferences(JSONObject json) { + Set externalDocumentRefs = new HashSet<>(); + JSONArray arrayExternalDocumentRefs = json.getJSONArray("externalDocumentRefs"); + if (arrayExternalDocumentRefs == null) { + return externalDocumentRefs; + } + for (int i = 0; i < arrayExternalDocumentRefs.length(); i++) { + try { + JSONObject objectExternalDocumentRef = arrayExternalDocumentRefs.getJSONObject(i); + JSONObject objectChecksum = objectExternalDocumentRef.getJSONObject("checksum"); + objectExternalDocumentRef.remove("checksum"); + ExternalDocumentReferences externalDocumentRef = mapper.readValue(objectExternalDocumentRef.toJSONString(), ExternalDocumentReferences.class); + CheckSum checksum = mapper.readValue(objectChecksum.toJSONString(), CheckSum.class); + externalDocumentRef.setChecksum(checksum); + externalDocumentRefs.add(externalDocumentRef); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return externalDocumentRefs; + } + + private static Set parseCreator(JSONObject json) { + Set creator = new HashSet<>(); + JSONArray arrayCreator = json.getJSONArray("creator"); + if (arrayCreator == null) { + return creator; + } + for (int i = 0; i < arrayCreator.length(); i++) { + try { + creator.add(mapper.readValue(arrayCreator.getString(i), Creator.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return creator; + } + + private static PackageVerificationCode parsePackageVerificationCode(JSONObject json) { + PackageVerificationCode packageVerificationCode = new PackageVerificationCode(); + JSONObject objectPackageVerificationCode = json.getJSONObject("packageVerificationCode"); + if (objectPackageVerificationCode == null) { + return packageVerificationCode; + } + try { + packageVerificationCode = mapper.readValue(objectPackageVerificationCode.toJSONString(), + PackageVerificationCode.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return packageVerificationCode; + } + + private static Set parseChecksum(JSONObject json) { + Set checkSums = new HashSet<>(); + JSONArray arrayCheckSums = json.getJSONArray("checksums"); + if (arrayCheckSums == null) { + return checkSums; + } + for (int i = 0; i < arrayCheckSums.length(); i++) { + try { + checkSums.add(mapper.readValue(arrayCheckSums.getString(i), CheckSum.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return checkSums; + } + + private static Set parseExternalReference(JSONObject json) { + Set externalRefs = new HashSet<>(); + JSONArray arrayExternalRefs = json.getJSONArray("externalRefs"); + if (arrayExternalRefs == null) { + return externalRefs; + } + for (int i = 0; i < arrayExternalRefs.length(); i++) { + try { + externalRefs.add(mapper.readValue(arrayExternalRefs.getString(i), ExternalReference.class)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + return externalRefs; + } + +} \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/moderation/ModerationPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/moderation/ModerationPortlet.java index 9cd2cc0279..adefc8691d 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/moderation/ModerationPortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/moderation/ModerationPortlet.java @@ -56,6 +56,12 @@ import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.projects.ProjectLink; import org.eclipse.sw360.datahandler.thrift.projects.ProjectService; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformationService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocumentService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformationService; import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; import org.eclipse.sw360.datahandler.thrift.users.User; import org.eclipse.sw360.datahandler.thrift.users.UserGroup; @@ -600,6 +606,42 @@ private void acceptModerationRequest(User user, User requestingUser, ModerationR UserUtils.activateLiferayUser(request, moderationRequest.getUser()); } break; + case SPDXDOCUMENT: { + SPDXDocumentService.Iface SpdxDocumentClient = thriftClients.makeSPDXClient(); + if (moderationRequest.isRequestDocumentDelete()) { + SpdxDocumentClient.deleteSPDXDocument(moderationRequest.getDocumentId(), user); + } else { + SpdxDocumentClient.updateSPDXDocumentFromModerationRequest( + moderationRequest.getSPDXDocumentAdditions(), + moderationRequest.getSPDXDocumentDeletions(), + user); + } + } + break; + case SPDX_DOCUMENT_CREATION_INFO: { + DocumentCreationInformationService.Iface documentCreationInfoClient = thriftClients.makeSPDXDocumentInfoClient(); + if (moderationRequest.isRequestDocumentDelete()) { + documentCreationInfoClient.deleteDocumentCreationInformation(moderationRequest.getDocumentId(), user); + } else { + documentCreationInfoClient.updateDocumentCreationInfomationFromModerationRequest( + moderationRequest.getDocumentCreationInfoAdditions(), + moderationRequest.getDocumentCreationInfoDeletions(), + user); + } + } + break; + case SPDX_PACKAGE_INFO: { + PackageInformationService.Iface packageInfoClient = thriftClients.makeSPDXPackageInfoClient(); + if (moderationRequest.isRequestDocumentDelete()) { + packageInfoClient.deletePackageInformation(moderationRequest.getDocumentId(), user); + } else { + packageInfoClient.updatePackageInfomationFromModerationRequest( + moderationRequest.getPackageInfoAdditions(), + moderationRequest.getPackageInfoDeletions(), + user); + } + } + break; } } @@ -769,6 +811,15 @@ private void renderEditViewForId(RenderRequest request, RenderResponse response, case USER: renderUserModeration(request, response, moderationRequest, user); break; + case SPDXDOCUMENT: + renderSPDXDocumentModeration(request, response, moderationRequest, user); + break; + case SPDX_DOCUMENT_CREATION_INFO: + renderDocumentCreationInfoModeration(request, response, moderationRequest, user); + break; + case SPDX_PACKAGE_INFO: + renderPackageInfoModeration(request, response, moderationRequest, user); + break; } } } @@ -1002,6 +1053,93 @@ public void renderUserModeration(RenderRequest request, RenderResponse response include("/html/moderation/users/merge.jsp", request, response); } + public void renderSPDXDocumentModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { + final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); + Boolean is_used = false; + SPDXDocument actual_SPDXDocuemnt = null; + try { + SPDXDocumentService.Iface client = thriftClients.makeSPDXClient(); + actual_SPDXDocuemnt = client.getSPDXDocumentForEdit(moderationRequest.getDocumentId(), user); + request.setAttribute(PortalConstants.ACTUAL_SPDXDOCUMENT, actual_SPDXDocuemnt); + } catch (TException e) { + log.error("Could not retrieve SPDX Document", e); + } + + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (actual_SPDXDocuemnt == null) { + renderNextModeration(request, response, user, LanguageUtil.get(resourceBundle,"ignored.unretrievable.target"), thriftClients.makeModerationClient(), moderationRequest); + return; + } + + if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) + return; + + request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_SPDX_DOCUMENT); + if (moderationRequest.isRequestDocumentDelete()) { + include("/html/moderation/spdx/spdxdocument/delete.jsp", request, response); + } else { + include("/html/moderation/spdx/spdxdocument/merge.jsp", request, response); + } + } + + public void renderDocumentCreationInfoModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { + final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); + Boolean is_used = false; + DocumentCreationInformation actual_DocuemntCreationInfo = null; + try { + DocumentCreationInformationService.Iface client = thriftClients.makeSPDXDocumentInfoClient(); + actual_DocuemntCreationInfo = client.getDocumentCreationInfoForEdit(moderationRequest.getDocumentId(), user); + request.setAttribute(PortalConstants.ACTUAL_DOCUMENT_CREATION_INFO, actual_DocuemntCreationInfo); + } catch (TException e) { + log.error("Could not retrieve Document Creation Information", e); + } + + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (actual_DocuemntCreationInfo == null) { + renderNextModeration(request, response, user, LanguageUtil.get(resourceBundle,"ignored.unretrievable.target"), thriftClients.makeModerationClient(), moderationRequest); + return; + } + + if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) + return; + + request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_SPDX_DOCUMENT_CREATION_INFO); + if (moderationRequest.isRequestDocumentDelete()) { + include("/html/moderation/spdx/documentcreationinfo/delete.jsp", request, response); + } else { + include("/html/moderation/spdx/documentcreationinfo/merge.jsp", request, response); + } + } + + public void renderPackageInfoModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { + final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); + Boolean is_used = false; + PackageInformation actual_PackageInfo = null; + try { + PackageInformationService.Iface client = thriftClients.makeSPDXPackageInfoClient(); + actual_PackageInfo = client.getPackageInformationForEdit(moderationRequest.getDocumentId(), user); + request.setAttribute(PortalConstants.ACTUAL_PACKAGE_INFO, actual_PackageInfo); + } catch (TException e) { + log.error("Could not retrieve Package Information", e); + } + + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (actual_PackageInfo == null) { + renderNextModeration(request, response, user, LanguageUtil.get(resourceBundle,"ignored.unretrievable.target"), thriftClients.makeModerationClient(), moderationRequest); + return; + } + + if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) + return; + + request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_SPDX_PACKAGE_INFO); + if (moderationRequest.isRequestDocumentDelete()) { + include("/html/moderation/spdx/packageinfo/delete.jsp", request, response); + } else { + include("/html/moderation/spdx/packageinfo/merge.jsp", request, response); + } + } + @UsedAsLiferayAction public void applyFilters(ActionRequest request, ActionResponse response) throws PortletException, IOException { for (ModerationRequest._Fields moderationFilteredField : MODERATION_FILTERED_FIELDS) { diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java index b267e4e717..4177f2941b 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/projects/ProjectPortlet.java @@ -2683,8 +2683,6 @@ private Map setLicenseInfoWithObligations(PortletR obligationStatusMap = licenseObligation.getObligationStatusMap(); request.setAttribute(APPROVED_OBLIGATIONS_COUNT, getFulfilledObligationsCount(obligationStatusMap)); - request.setAttribute(OBLIGATION_FROM_README_OSS, getObligationsFromReadmeOSSCount(obligationStatusMap)); - request.setAttribute(EXCLUDED_RELEASES, excludedReleases); request.setAttribute(PROJECT_OBLIGATIONS_INFO_BY_RELEASE, filterAndSortLicenseInfo(licenseObligation.getLicenseInfoResults())); } catch (TException e) { @@ -2727,17 +2725,8 @@ private List filterAndSortLicenseInfo(List obligationStatusMap) { if (CommonUtils.isNotEmpty(obligationStatusMap.keySet())) { - return Math.toIntExact( - obligationStatusMap.values().stream().filter(obligation -> obligation.getStatus() != null - && !ObligationStatus.OPEN.equals(obligation.getStatus())).count()); - } - return 0; - } - - private int getObligationsFromReadmeOSSCount(Map obligationStatusMap) { - if (CommonUtils.isNotEmpty(obligationStatusMap.keySet())) { - return Math.toIntExact( - obligationStatusMap.values().stream().filter(obligation -> obligation.getObligationLevel() == null).count()); + return Math.toIntExact(obligationStatusMap.values().stream() + .filter(obligation -> ObligationStatus.ACKNOWLEDGED_OR_FULFILLED.equals(obligation.getStatus())).count()); } return 0; } diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayDocumentCreationInfoChanges.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayDocumentCreationInfoChanges.java new file mode 100644 index 0000000000..94f076f41e --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayDocumentCreationInfoChanges.java @@ -0,0 +1,302 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.portal.tags; + +import com.google.common.base.Strings; +import org.apache.commons.lang.StringEscapeUtils; +import com.liferay.portal.kernel.language.LanguageUtil; +import com.liferay.portal.kernel.util.ResourceBundleUtil; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; + +import org.apache.thrift.meta_data.FieldMetaData; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspWriter; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.ResourceBundle; +import java.util.Set; + +import static org.eclipse.sw360.portal.tags.TagUtils.*; + +public class DisplayDocumentCreationInfoChanges extends UserAwareTag { + private DocumentCreationInformation actual; + private DocumentCreationInformation additions; + private DocumentCreationInformation deletions; + private String tableClasses = ""; + private String idPrefix = ""; + + public void setActual(DocumentCreationInformation actual) { + this.actual = actual; + } + + public void setAdditions(DocumentCreationInformation additions) { + this.additions = additions; + } + + public void setDeletions(DocumentCreationInformation deletions) { + this.deletions = deletions; + } + + public void setTableClasses(String tableClasses) { + this.tableClasses = tableClasses; + } + + public void setIdPrefix(String idPrefix) { + this.idPrefix = idPrefix; + } + + public int doStartTag() throws JspException { + + JspWriter jspWriter = pageContext.getOut(); + + StringBuilder display = new StringBuilder(); + + if (additions == null || deletions == null) { + return SKIP_BODY; + } + + try { + for (DocumentCreationInformation._Fields field : DocumentCreationInformation._Fields.values()) { + switch (field) { + // ignored Fields + case ID: + case REVISION: + case TYPE: + case CREATED_BY: + case PERMISSIONS: + case DOCUMENT_STATE: + case EXTERNAL_DOCUMENT_REFS: + case CREATOR: + break; + default: + FieldMetaData fieldMetaData = DocumentCreationInformation.metaDataMap.get(field); + displaySimpleFieldOrSet(display, actual, additions, deletions, field, fieldMetaData, "", false); + } + } + + String renderString = display.toString(); + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), + getClass()); + + if (Strings.isNullOrEmpty(renderString)) { + renderString = "
" + + LanguageUtil.get(resourceBundle, "no.changes.in.basic.fields") + "
"; + } else { + renderString = String.format("", tableClasses, idPrefix) + + "" + + String.format("", + LanguageUtil.get(resourceBundle, "field.name"), + LanguageUtil.get(resourceBundle, "current.value"), + LanguageUtil.get(resourceBundle, "former.value"), + LanguageUtil.get(resourceBundle, "suggested.value")) + + renderString + "
" + LanguageUtil.get(resourceBundle, "changes.for.basic.fields") + + "
%s%s%s%s
"; + } + String externalDocumentRefsRenderString = renderExternalDocumentRefs(); + String creatorRenderString = renderCreator(); + jspWriter.print(renderString + externalDocumentRefsRenderString.toString() + creatorRenderString.toString()); + } catch (Exception e) { + throw new JspException(e); + } + return SKIP_BODY; + } + + private boolean ensureSomethingTodoAndNoNull(DocumentCreationInformation._Fields field) { + if (!deletions.isSet(field) && !additions.isSet(field)) { + return false; + } + + if (field == DocumentCreationInformation._Fields.EXTERNAL_DOCUMENT_REFS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == DocumentCreationInformation._Fields.CREATOR){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } + return true; + } + + private String renderExternalDocumentRefs() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(DocumentCreationInformation._Fields.EXTERNAL_DOCUMENT_REFS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(DocumentCreationInformation._Fields.EXTERNAL_DOCUMENT_REFS)){ + actual.externalDocumentRefs = new HashSet<>(); + } + + Set additionsExternalDocumentRefs = additions.getExternalDocumentRefs(); + Set deletionsExternalDocumentRefs = deletions.getExternalDocumentRefs(); + Set currentExternalDocumentRefs = actual.getExternalDocumentRefs(); + int changeSize = 0; + if (additionsExternalDocumentRefs.size() > deletionsExternalDocumentRefs.size()) { + changeSize = additionsExternalDocumentRefs.size() + currentExternalDocumentRefs.size() - deletionsExternalDocumentRefs.size(); + } else { + changeSize = currentExternalDocumentRefs.size(); + } + + for (int i = 0; i < changeSize; i++) { + ExternalDocumentReferences externalDocumentRefDeletions = getExternalDocumentRefsByIndex(deletions, i); + ExternalDocumentReferences externalDocumentRefAdditions = getExternalDocumentRefsByIndex(additions, i); + ExternalDocumentReferences externalDocumentRef = getExternalDocumentRefsByIndex(actual, i); + String checkSumRendeString = null; + + for (ExternalDocumentReferences._Fields field : ExternalDocumentReferences._Fields.values()) { + FieldMetaData fieldMetaData = ExternalDocumentReferences.metaDataMap.get(field); + if (field == ExternalDocumentReferences._Fields.CHECKSUM) { + checkSumRendeString = renderCheckSum(externalDocumentRef, externalDocumentRefAdditions, externalDocumentRefDeletions); + } else { + displaySimpleFieldOrSet( + display, + externalDocumentRef, + externalDocumentRefAdditions, + externalDocumentRefDeletions, + field, fieldMetaData, "", false); + } + } + if (checkSumRendeString != null) { + display.append(checkSumRendeString); + } + } + return "

"+LanguageUtil.get(resourceBundle,"changes.in.external.document.references")+ "

" + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
%s%s%s%s
"; + } + + private ExternalDocumentReferences getExternalDocumentRefsByIndex(DocumentCreationInformation document, int index) { + ExternalDocumentReferences externalDocumentRefs; + Iterator externalDocumentRefsIterator = document.getExternalDocumentRefsIterator(); + while (externalDocumentRefsIterator.hasNext()) { + externalDocumentRefs = externalDocumentRefsIterator.next(); + if (externalDocumentRefs.getIndex() == index) { + externalDocumentRefs.setIndex(0); // Set 0 to not show Index when add or delete + return externalDocumentRefs; + } + } + return new ExternalDocumentReferences(); + } + + private String renderCreator() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(DocumentCreationInformation._Fields.CREATOR)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(DocumentCreationInformation._Fields.CREATOR)){ + actual.creator = new HashSet<>(); + } + + Set additionsCreators = additions.getCreator(); + Set deletionsCreators = deletions.getCreator(); + Set currentCreators = actual.getCreator(); + int changeSize = 0; + if (additionsCreators.size() > deletionsCreators.size()) { + changeSize = additionsCreators.size() + currentCreators.size() - deletionsCreators.size(); + } else { + changeSize = currentCreators.size(); + } + + for (int i = 0; i < changeSize; i++) { + Creator creatorDeletions = getCreatorByIndex(deletions, i); + Creator creatorAdditions = getCreatorByIndex(additions, i); + Creator creator = getCreatorByIndex(actual, i); + + for (Creator._Fields field : Creator._Fields.values()) { + FieldMetaData fieldMetaData = Creator.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + creator, + creatorAdditions, + creatorDeletions, + field, fieldMetaData, "", false); + } + } + return "

"+LanguageUtil.get(resourceBundle,"changes.in.creator")+ "

" + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
%s%s%s%s
"; + } + + private Creator getCreatorByIndex(DocumentCreationInformation document, int index) { + Creator creator; + Iterator creatorIterator = document.getCreatorIterator(); + while (creatorIterator.hasNext()) { + creator = creatorIterator.next(); + if (creator.getIndex() == index) { + creator.setIndex(0); // Set 0 to not show Index when add or delete + return creator; + } + } + return new Creator(); + } + + private String renderCheckSum(ExternalDocumentReferences actualChecsum, ExternalDocumentReferences additionsChecsum, ExternalDocumentReferences deletionsChecsum) { + + if (!deletionsChecsum.isSet(ExternalDocumentReferences._Fields.CHECKSUM) + && !additionsChecsum.isSet(ExternalDocumentReferences._Fields.CHECKSUM)) { + return ""; + } + + if (!actualChecsum.isSet(ExternalDocumentReferences._Fields.CHECKSUM)) { + actualChecsum.checksum = new CheckSum(); + actualChecsum.checksum.algorithm = NOT_SET; + actualChecsum.checksum.checksumValue = NOT_SET; + } + + if (!deletionsChecsum.isSet(ExternalDocumentReferences._Fields.CHECKSUM)) { + deletionsChecsum.checksum = new CheckSum(); + deletionsChecsum.checksum.algorithm = NOT_SET; + deletionsChecsum.checksum.checksumValue = NOT_SET; + } + + if (!additionsChecsum.isSet(ExternalDocumentReferences._Fields.CHECKSUM)) { + additionsChecsum.checksum = new CheckSum(); + additionsChecsum.checksum.algorithm = NOT_SET; + additionsChecsum.checksum.checksumValue = NOT_SET; + } + + if (actualChecsum.checksum.algorithm.equals(additionsChecsum.checksum.algorithm) + && actualChecsum.checksum.checksumValue.equals(additionsChecsum.checksum.checksumValue)) { + return ""; + } + + String display = " CheckSum:
  • algorithm: " + + StringEscapeUtils.escapeXml(actualChecsum.checksum.algorithm) + "
  • checksumValue: " + + StringEscapeUtils.escapeXml(actualChecsum.checksum.checksumValue) + "
  • algorithm: " + + StringEscapeUtils.escapeXml(deletionsChecsum.checksum.algorithm) + "
  • checksumValue: " + + StringEscapeUtils.escapeXml(deletionsChecsum.checksum.checksumValue) + "
  • algorithm: " + + StringEscapeUtils.escapeXml(additionsChecsum.checksum.algorithm) + "
  • checksumValue: " + + StringEscapeUtils.escapeXml(additionsChecsum.checksum.checksumValue) + "
  • "; + return display; + } + +} diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayPackageInfoChanges.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayPackageInfoChanges.java new file mode 100644 index 0000000000..da0a9017ed --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayPackageInfoChanges.java @@ -0,0 +1,360 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.portal.tags; + +import com.google.common.base.Strings; +import com.liferay.portal.kernel.language.LanguageUtil; +import com.liferay.portal.kernel.util.ResourceBundleUtil; + +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; +import org.apache.thrift.meta_data.FieldMetaData; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspWriter; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.ResourceBundle; +import java.util.Set; + +import static org.eclipse.sw360.portal.tags.TagUtils.*; + +public class DisplayPackageInfoChanges extends UserAwareTag { + private PackageInformation actual; + private PackageInformation additions; + private PackageInformation deletions; + private String tableClasses = ""; + private String idPrefix = ""; + + public void setActual(PackageInformation actual) { + this.actual = actual; + } + + public void setAdditions(PackageInformation additions) { + this.additions = additions; + } + + public void setDeletions(PackageInformation deletions) { + this.deletions = deletions; + } + + public void setTableClasses(String tableClasses) { + this.tableClasses = tableClasses; + } + + public void setIdPrefix(String idPrefix) { + this.idPrefix = idPrefix; + } + + public int doStartTag() throws JspException { + + JspWriter jspWriter = pageContext.getOut(); + + StringBuilder display = new StringBuilder(); + + if (additions == null || deletions == null) { + return SKIP_BODY; + } + + try { + for (PackageInformation._Fields field : PackageInformation._Fields.values()) { + switch (field) { + // ignored Fields + case ID: + case REVISION: + case TYPE: + case CREATED_BY: + case PERMISSIONS: + case DOCUMENT_STATE: + case PACKAGE_VERIFICATION_CODE: + case ANNOTATIONS: + case CHECKSUMS: + case EXTERNAL_REFS: + break; + default: + FieldMetaData fieldMetaData = PackageInformation.metaDataMap.get(field); + displaySimpleFieldOrSet(display, actual, additions, deletions, field, fieldMetaData, "", false); + } + } + + String renderString = display.toString(); + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), + getClass()); + + if (Strings.isNullOrEmpty(renderString)) { + renderString = "
    " + + LanguageUtil.get(resourceBundle, "no.changes.in.basic.fields") + "
    "; + } else { + renderString = String.format("", tableClasses, idPrefix) + + "" + + String.format("", + LanguageUtil.get(resourceBundle, "field.name"), + LanguageUtil.get(resourceBundle, "current.value"), + LanguageUtil.get(resourceBundle, "former.value"), + LanguageUtil.get(resourceBundle, "suggested.value")) + + renderString + "
    " + LanguageUtil.get(resourceBundle, "changes.for.basic.fields") + + "
    %s%s%s%s
    "; + } + String packageVerificationCodeRenderString = renderPackageVerificationCode(); + String annotaionsRenderString = renderAnnotaions(); + String checkSumRenderString = renderCheckSum(); + String externalReferenceRenderString = renderExternalReference(); + jspWriter.print(renderString + packageVerificationCodeRenderString.toString() + checkSumRenderString.toString() + externalReferenceRenderString.toString() + annotaionsRenderString.toString()); + } catch (Exception e) { + throw new JspException(e); + } + return SKIP_BODY; + } + + private boolean ensureSomethingTodoAndNoNull(PackageInformation._Fields field) { + if (!deletions.isSet(field) && !additions.isSet(field)) { + return false; + } + + if (field == PackageInformation._Fields.CHECKSUMS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == PackageInformation._Fields.EXTERNAL_REFS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == PackageInformation._Fields.ANNOTATIONS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == PackageInformation._Fields.PACKAGE_VERIFICATION_CODE){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } + + return true; + } + + private String renderCheckSum() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(PackageInformation._Fields.CHECKSUMS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(PackageInformation._Fields.CHECKSUMS)){ + actual.checksums = new HashSet<>(); + } + + Set additionsCheckSums = additions.getChecksums(); + Set deletionsCheckSums = deletions.getChecksums(); + Set currentCheckSums = actual.getChecksums(); + int changeSize = 0; + if (additionsCheckSums.size() > deletionsCheckSums.size()) { + changeSize = additionsCheckSums.size() + currentCheckSums.size() - deletionsCheckSums.size(); + } else { + changeSize = currentCheckSums.size(); + } + + for (int i = 0; i < changeSize; i++) { + CheckSum checkSumDeletions = getChecksumsByIndex(deletions, i); + CheckSum checkSumAdditions = getChecksumsByIndex(additions, i); + CheckSum checkSum = getChecksumsByIndex(actual, i); + + for (CheckSum._Fields field : CheckSum._Fields.values()) { + FieldMetaData fieldMetaData = CheckSum.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + checkSum, + checkSumAdditions, + checkSumDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.checksum")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private CheckSum getChecksumsByIndex(PackageInformation packageInfo, int index) { + CheckSum checksum; + Iterator checksumIterator = packageInfo.getChecksumsIterator(); + while (checksumIterator.hasNext()) { + checksum = checksumIterator.next(); + if (checksum.getIndex() == index) { + checksum.setIndex(0); // Set 0 to not show Index when add or delete + return checksum; + } + } + return new CheckSum(); + } + + private String renderAnnotaions() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(PackageInformation._Fields.ANNOTATIONS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(PackageInformation._Fields.ANNOTATIONS)){ + actual.annotations = new HashSet<>(); + } + + Set additionsAnnotations = additions.getAnnotations(); + Set deletionsAnnotations = deletions.getAnnotations(); + Set currentAnnotations = actual.getAnnotations(); + int changeSize = 0; + if (additionsAnnotations.size() > deletionsAnnotations.size()) { + changeSize = additionsAnnotations.size() + currentAnnotations.size() - deletionsAnnotations.size(); + } else { + changeSize = currentAnnotations.size(); + } + + for (int i = 0; i < changeSize; i++) { + Annotations annotationDeletions = getAnnotationsByIndex(deletions, i); + Annotations annotationAdditions = getAnnotationsByIndex(additions, i); + Annotations annotation = getAnnotationsByIndex(actual, i); + + for (Annotations._Fields field : Annotations._Fields.values()) { + FieldMetaData fieldMetaData = Annotations.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + annotation, + annotationAdditions, + annotationDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.annotaions.information")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private Annotations getAnnotationsByIndex(PackageInformation packageInfo, int index) { + Annotations annotations; + Iterator annotationsIterator = packageInfo.getAnnotationsIterator(); + while (annotationsIterator.hasNext()) { + annotations = annotationsIterator.next(); + if (annotations.getIndex() == index) { + annotations.setIndex(0); // Set 0 to not show Index when add or delete + return annotations; + } + } + return new Annotations(); + } + + private String renderExternalReference() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(PackageInformation._Fields.EXTERNAL_REFS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(PackageInformation._Fields.EXTERNAL_REFS)){ + actual.externalRefs = new HashSet<>(); + } + + Set additionsExternalReferences = additions.getExternalRefs(); + Set deletionsExternalReferences = deletions.getExternalRefs(); + Set currentExternalReferences = actual.getExternalRefs(); + int changeSize = 0; + if (additionsExternalReferences.size() > deletionsExternalReferences.size()) { + changeSize = additionsExternalReferences.size() + currentExternalReferences.size() - deletionsExternalReferences.size(); + } else { + changeSize = currentExternalReferences.size(); + } + + for (int i = 0; i < changeSize; i++) { + ExternalReference externalRefDeletions = getExternalReferenceByIndex(deletions, i); + ExternalReference externalRefAdditions = getExternalReferenceByIndex(additions, i); + ExternalReference externalRef = getExternalReferenceByIndex(actual, i); + + for (ExternalReference._Fields field : ExternalReference._Fields.values()) { + FieldMetaData fieldMetaData = ExternalReference.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + externalRef, + externalRefAdditions, + externalRefDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.external.references")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private ExternalReference getExternalReferenceByIndex(PackageInformation packageInfo, int index) { + ExternalReference externalReference; + Iterator externalReferenceIterator = packageInfo.getExternalRefsIterator(); + while (externalReferenceIterator.hasNext()) { + externalReference = externalReferenceIterator.next(); + if (externalReference.getIndex() == index) { + externalReference.setIndex(0); // Set 0 to not show Index when add or delete + return externalReference; + } + } + return new ExternalReference(); + } + + private String renderPackageVerificationCode() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(PackageInformation._Fields.PACKAGE_VERIFICATION_CODE)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(PackageInformation._Fields.PACKAGE_VERIFICATION_CODE)){ + actual.packageVerificationCode = new PackageVerificationCode(); + } + + for (PackageVerificationCode._Fields field : PackageVerificationCode._Fields.values()) { + FieldMetaData fieldMetaData = PackageVerificationCode.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + actual.getPackageVerificationCode(), + additions.getPackageVerificationCode(), + deletions.getPackageVerificationCode(), + field, fieldMetaData, "", false); + } + + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.package.verification.code")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } +} \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplaySPDXDocumentChanges.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplaySPDXDocumentChanges.java new file mode 100644 index 0000000000..3a46e13774 --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplaySPDXDocumentChanges.java @@ -0,0 +1,476 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.portal.tags; + +import com.google.common.base.Strings; +import org.apache.commons.lang.StringEscapeUtils; +import com.liferay.portal.kernel.language.LanguageUtil; +import com.liferay.portal.kernel.util.ResourceBundleUtil; + +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetRange; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.apache.thrift.meta_data.FieldMetaData; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspWriter; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.ResourceBundle; +import java.util.Set; + +import static org.eclipse.sw360.portal.tags.TagUtils.*; + +public class DisplaySPDXDocumentChanges extends UserAwareTag { + private SPDXDocument actual; + private SPDXDocument additions; + private SPDXDocument deletions; + private String tableClasses = ""; + private String idPrefix = ""; + + public void setActual(SPDXDocument actual) { + this.actual = actual; + } + + public void setAdditions(SPDXDocument additions) { + this.additions = additions; + } + + public void setDeletions(SPDXDocument deletions) { + this.deletions = deletions; + } + + public void setTableClasses(String tableClasses) { + this.tableClasses = tableClasses; + } + + public void setIdPrefix(String idPrefix) { + this.idPrefix = idPrefix; + } + + public int doStartTag() throws JspException { + + JspWriter jspWriter = pageContext.getOut(); + + StringBuilder display = new StringBuilder(); + + if (additions == null || deletions == null) { + return SKIP_BODY; + } + + try { + for (SPDXDocument._Fields field : SPDXDocument._Fields.values()) { + switch (field) { + // ignored Fields + case ID: + case REVISION: + case TYPE: + case CREATED_BY: + case PERMISSIONS: + case DOCUMENT_STATE: + case OTHER_LICENSING_INFORMATION_DETECTEDS: + case SNIPPETS: + case ANNOTATIONS: + case RELATIONSHIPS: + break; + default: + FieldMetaData fieldMetaData = SPDXDocument.metaDataMap.get(field); + displaySimpleFieldOrSet(display, actual, additions, deletions, field, fieldMetaData, "", false); + } + } + + String renderString = display.toString(); + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), + getClass()); + + if (Strings.isNullOrEmpty(renderString)) { + renderString = "
    " + + LanguageUtil.get(resourceBundle, "no.changes.in.basic.fields") + "
    "; + } else { + renderString = String.format("", tableClasses, idPrefix) + + "" + + String.format("", + LanguageUtil.get(resourceBundle, "field.name"), + LanguageUtil.get(resourceBundle, "current.value"), + LanguageUtil.get(resourceBundle, "former.value"), + LanguageUtil.get(resourceBundle, "suggested.value")) + + renderString + "
    " + LanguageUtil.get(resourceBundle, "changes.for.basic.fields") + + "
    %s%s%s%s
    "; + } + String snippetRenderString = renderSnippetInformation(); + String relationshipSRenderString = renderRelationshipInformation(); + String annotaionsRenderString = renderAnnotaionsInformation(); + String otherLicensingRenderString = renderOtherLicensingInformationDetected(); + jspWriter.print(renderString + snippetRenderString.toString() + + relationshipSRenderString.toString() + + annotaionsRenderString.toString() + + otherLicensingRenderString.toString()); + } catch (Exception e) { + throw new JspException(e); + } + return SKIP_BODY; + } + + private boolean ensureSomethingTodoAndNoNull(SPDXDocument._Fields field) { + if (!deletions.isSet(field) && !additions.isSet(field)) { + return false; + } + + if (field == SPDXDocument._Fields.SNIPPETS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == SPDXDocument._Fields.RELATIONSHIPS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == SPDXDocument._Fields.ANNOTATIONS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } else if (field == SPDXDocument._Fields.OTHER_LICENSING_INFORMATION_DETECTEDS){ + if (!deletions.isSet(field)) { + deletions.setFieldValue(field, new HashSet<>()); + } + if (!additions.isSet(field)) { + additions.setFieldValue(field, new HashSet<>()); + } + } + return true; + } + + private String renderSnippetInformation() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(SPDXDocument._Fields.SNIPPETS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(SPDXDocument._Fields.SNIPPETS)){ + actual.snippets = new HashSet<>(); + } + + Set additionsSnippetInformations = additions.getSnippets(); + Set deletionsSnippetInformations = deletions.getSnippets(); + Set currentSnippetInformations = actual.getSnippets(); + int changeSize = 0; + if (additionsSnippetInformations.size() > deletionsSnippetInformations.size()) { + changeSize = additionsSnippetInformations.size() + currentSnippetInformations.size() - deletionsSnippetInformations.size(); + } else { + changeSize = currentSnippetInformations.size(); + } + + for (int i = 0; i < changeSize; i++) { + SnippetInformation snippetDeletions = getSnippetInformationByIndex(deletions, i); + SnippetInformation snippetAdditions = getSnippetInformationByIndex(additions, i); + SnippetInformation snippet = getSnippetInformationByIndex(actual, i); + + String snippetRangeRendeString = null; + for (SnippetInformation._Fields field : SnippetInformation._Fields.values()) { + FieldMetaData fieldMetaData = SnippetInformation.metaDataMap.get(field); + if (field == SnippetInformation._Fields.SNIPPET_RANGES) { + snippetRangeRendeString = renderSnippetRange(snippet, snippetAdditions, snippetDeletions); + } else { + displaySimpleFieldOrSet( + display, + snippet, + snippetAdditions, + snippetDeletions, + field, fieldMetaData, "", false); + } + } + if (snippetRangeRendeString != null) { + display.append(snippetRangeRendeString); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.snippets.information")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private SnippetInformation getSnippetInformationByIndex(SPDXDocument spdx, int index) { + SnippetInformation snippet; + Iterator snippetsIterator = spdx.getSnippetsIterator(); + while (snippetsIterator.hasNext()) { + snippet = snippetsIterator.next(); + if (snippet.getIndex() == index) { + snippet.setIndex(0); // Set 0 to not show Index when add or delete + return snippet; + } + } + return new SnippetInformation(); + } + + private String renderRelationshipInformation() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(SPDXDocument._Fields.RELATIONSHIPS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(SPDXDocument._Fields.RELATIONSHIPS)){ + actual.relationships = new HashSet<>(); + } + + Set additionsRelationshipsBetweenSPDXElementss = additions.getRelationships(); + Set deletionsRelationshipsBetweenSPDXElementss = deletions.getRelationships(); + Set currentRelationshipsBetweenSPDXElementss = actual.getRelationships(); + int changeSize = 0; + if (additionsRelationshipsBetweenSPDXElementss.size() > deletionsRelationshipsBetweenSPDXElementss.size()) { + changeSize = additionsRelationshipsBetweenSPDXElementss.size() + currentRelationshipsBetweenSPDXElementss.size() + - deletionsRelationshipsBetweenSPDXElementss.size(); + } else { + changeSize = currentRelationshipsBetweenSPDXElementss.size(); + } + + for (int i = 0; i < changeSize; i++) { + + RelationshipsBetweenSPDXElements relationshipDeletions = getRelationshipByIndex(deletions, i); + RelationshipsBetweenSPDXElements relationshipAdditions = getRelationshipByIndex(additions, i); + RelationshipsBetweenSPDXElements relationship = getRelationshipByIndex(actual, i); + + for (RelationshipsBetweenSPDXElements._Fields field : RelationshipsBetweenSPDXElements._Fields.values()) { + FieldMetaData fieldMetaData = RelationshipsBetweenSPDXElements.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + relationship, + relationshipAdditions, + relationshipDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.relationship.information")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private RelationshipsBetweenSPDXElements getRelationshipByIndex(SPDXDocument spdx, int index) { + RelationshipsBetweenSPDXElements relationship; + Iterator relationshipIterator = spdx.getRelationshipsIterator(); + while (relationshipIterator.hasNext()) { + relationship = relationshipIterator.next(); + if (relationship.getIndex() == index) { + return relationship; // Set 0 to not show Index when add or delete + } + } + return new RelationshipsBetweenSPDXElements(); + } + + private String renderAnnotaionsInformation() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(SPDXDocument._Fields.ANNOTATIONS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(SPDXDocument._Fields.ANNOTATIONS)){ + actual.annotations = new HashSet<>(); + } + + Set additionsAnnotations = additions.getAnnotations(); + Set deletionsAnnotations = deletions.getAnnotations(); + Set currentAnnotations = actual.getAnnotations(); + int changeSize = 0; + if (additionsAnnotations.size() > deletionsAnnotations.size()) { + changeSize = additionsAnnotations.size() + currentAnnotations.size() - deletionsAnnotations.size(); + } else { + changeSize = currentAnnotations.size(); + } + + for (int i = 0; i < changeSize; i++) { + Annotations annotationDeletions = getAnnotationsByIndex(deletions, i); + Annotations annotationAdditions = getAnnotationsByIndex(additions, i); + Annotations annotation = getAnnotationsByIndex(actual, i); + + for (Annotations._Fields field : Annotations._Fields.values()) { + FieldMetaData fieldMetaData = Annotations.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + annotation, + annotationAdditions, + annotationDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.annotaions.information")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private Annotations getAnnotationsByIndex(SPDXDocument spdx, int index) { + Annotations annotations; + Iterator annotationsIterator = spdx.getAnnotationsIterator(); + while (annotationsIterator.hasNext()) { + annotations = annotationsIterator.next(); + if (annotations.getIndex() == index) { + annotations.setIndex(0); // Set 0 to not show Index when add or delete + return annotations; + } + } + return new Annotations(); + } + + private String renderOtherLicensingInformationDetected() { + HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); + ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + if (!ensureSomethingTodoAndNoNull(SPDXDocument._Fields.OTHER_LICENSING_INFORMATION_DETECTEDS)) { + return ""; + } + StringBuilder display = new StringBuilder(); + if (! actual.isSet(SPDXDocument._Fields.OTHER_LICENSING_INFORMATION_DETECTEDS)){ + actual.otherLicensingInformationDetecteds = new HashSet<>(); + } + + Set additionsOtherLicensingInformationDetecteds = additions.getOtherLicensingInformationDetecteds(); + Set deletionsOtherLicensingInformationDetecteds = deletions.getOtherLicensingInformationDetecteds(); + Set currentOtherLicensingInformationDetecteds = actual.getOtherLicensingInformationDetecteds(); + int changeSize = 0; + if (additionsOtherLicensingInformationDetecteds.size() > deletionsOtherLicensingInformationDetecteds.size()) { + changeSize = additionsOtherLicensingInformationDetecteds.size() + + currentOtherLicensingInformationDetecteds.size() + - deletionsOtherLicensingInformationDetecteds.size(); + } else { + changeSize = currentOtherLicensingInformationDetecteds.size(); + } + + for (int i = 0; i < changeSize; i++) { + OtherLicensingInformationDetected otherLicensingDeletions = getOtherLicensingByIndex(deletions, i); + OtherLicensingInformationDetected otherLicensingAdditions = getOtherLicensingByIndex(additions, i); + OtherLicensingInformationDetected otherLicensing = getOtherLicensingByIndex(actual, i); + for (OtherLicensingInformationDetected._Fields field : OtherLicensingInformationDetected._Fields.values()) { + FieldMetaData fieldMetaData = OtherLicensingInformationDetected.metaDataMap.get(field); + displaySimpleFieldOrSet( + display, + otherLicensing, + otherLicensingAdditions, + otherLicensingDeletions, + field, fieldMetaData, "", false); + } + } + return "

    "+LanguageUtil.get(resourceBundle,"changes.in.other.licensing.information.detecteds")+ "

    " + + String.format("", tableClasses, idPrefix) + + String.format("", + LanguageUtil.get(resourceBundle,"field.name"), LanguageUtil.get(resourceBundle,"current.value"), + LanguageUtil.get(resourceBundle,"former.value"), LanguageUtil.get(resourceBundle,"suggested.value")) + + display.toString() + "
    %s%s%s%s
    "; + } + + private OtherLicensingInformationDetected getOtherLicensingByIndex(SPDXDocument spdx, int index) { + OtherLicensingInformationDetected otherLicensing; + Iterator otherLicensingIterator = spdx.getOtherLicensingInformationDetectedsIterator(); + while (otherLicensingIterator.hasNext()) { + otherLicensing = otherLicensingIterator.next(); + if (otherLicensing.getIndex() == index) { + otherLicensing.setIndex(0); // Set 0 to not show Index when add or delete + return otherLicensing; + } + } + return new OtherLicensingInformationDetected(); + } + + private String renderSnippetRange(SnippetInformation actual, SnippetInformation additions, SnippetInformation deletions) { + StringBuilder display = new StringBuilder(); + display.append("snippetRange:"); + if (! actual.isSet(SnippetInformation._Fields.SNIPPET_RANGES)){ + actual.snippetRanges = new HashSet<>(); + } + if (! additions.isSet(SnippetInformation._Fields.SNIPPET_RANGES)){ + additions.snippetRanges = new HashSet<>(); + } + if (! deletions.isSet(SnippetInformation._Fields.SNIPPET_RANGES)){ + deletions.snippetRanges = new HashSet<>(); + } + if (additions.snippetRanges.isEmpty() && deletions.snippetRanges.isEmpty()) { + return ""; + } + + Set additionsSnippetRanges = additions.getSnippetRanges(); + Set deletionsSnippetRanges = deletions.getSnippetRanges(); + Set currentSnippetRanges = actual.getSnippetRanges(); + int changeSize = 0; + if (additionsSnippetRanges.size() > deletionsSnippetRanges.size()) { + changeSize = additionsSnippetRanges.size() + currentSnippetRanges.size() - deletionsSnippetRanges.size(); + } else { + changeSize = currentSnippetRanges.size(); + } + + for (int i = 0; i < changeSize; i++) { + SnippetRange snippetRangeDeletions = getSnippetRangeByIndex(deletions, i); + SnippetRange snippetRangeAdditions = getSnippetRangeByIndex(additions, i); + SnippetRange snippetRange = getSnippetRangeByIndex(actual, i); + String renderActual = ""; + String renderDeletions = ""; + String renderAdditions = ""; + + for (SnippetRange._Fields field : SnippetRange._Fields.values()) { + if (snippetRange.getFieldValue(field) == null) { + snippetRange.setFieldValue(field, NOT_SET); + } + if (snippetRangeAdditions.getFieldValue(field) == null) { + snippetRangeAdditions.setFieldValue(field, NOT_SET); + } + if (snippetRangeDeletions.getFieldValue(field) == null) { + snippetRangeDeletions.setFieldValue(field, NOT_SET); + } + if (!snippetRange.equals(snippetRangeAdditions) && !SnippetRange._Fields.INDEX.equals(field)) { + renderActual = renderActual + "
  • " + field.getFieldName() + ": " + StringEscapeUtils.escapeXml(snippetRange.getFieldValue(field).toString()) + "
  • "; + renderDeletions = renderDeletions + "
  • " + field.getFieldName() + ": " + StringEscapeUtils.escapeXml(snippetRangeDeletions.getFieldValue(field).toString()) + "
  • "; + renderAdditions = renderAdditions + "
  • " + field.getFieldName() + ": " + StringEscapeUtils.escapeXml(snippetRangeAdditions.getFieldValue(field).toString()) + "
  • "; + } + } + String renderTotal = "
      " + renderActual + "
      " + + renderDeletions + "
      " + + renderAdditions + "
    "; + if (renderActual != "") { + display.append(renderTotal); + } + } + return display.toString(); + } + + private SnippetRange getSnippetRangeByIndex(SnippetInformation snippet, int index) { + SnippetRange snippetRange; + Iterator snippetRangeIterator = snippet.getSnippetRangesIterator(); + while (snippetRangeIterator.hasNext()) { + snippetRange = snippetRangeIterator.next(); + if (snippetRange.getIndex() == index) { + snippet.setIndex(0); // Set 0 to not show Index when add or delete + return snippetRange; + } + } + return new SnippetRange(); + } + +} \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/OutTag.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/OutTag.java index 53a4205516..485ee10d14 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/OutTag.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/OutTag.java @@ -30,6 +30,7 @@ public class OutTag extends OutSupport { private boolean jsQuoting = false; private boolean stripNewlines = true; + private boolean hashSet = false; private boolean bare = false; private Integer maxChar = -1; @@ -58,6 +59,11 @@ public int doStartTag() throws JspException { candidate = candidate.replaceAll("[\r\n]+", " "); } + if (hashSet) { + candidate = StringUtils.removeStart(candidate, "["); + candidate = StringUtils.chop(candidate); + } + this.value = candidate; if (!bare && abbreviated) { @@ -95,6 +101,10 @@ public void setStripNewlines(boolean stripNewlines) { this.stripNewlines = stripNewlines; } + public void setHashSet(boolean hashSet) { + this.hashSet = hashSet; + } + public void setBare(boolean bare) { this.bare = bare; } private String prepareTitleAttribute(String value) { diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/customTags.tld b/frontend/sw360-portlet/src/main/resources/META-INF/customTags.tld index be4350eb97..987639f889 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/customTags.tld +++ b/frontend/sw360-portlet/src/main/resources/META-INF/customTags.tld @@ -1206,6 +1206,12 @@ java.lang.Boolean true + + hashSet + false + java.lang.Boolean + true + maxChar false @@ -1381,4 +1387,128 @@ org.eclipse.sw360.datahandler.common.SW360Utils java.lang.String printName(org.eclipse.sw360.datahandler.thrift.users.User) + + + printSPDXDocumentName + org.eclipse.sw360.datahandler.common.SW360Utils + java.lang.String printName(org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument) + + + printDocumentCreationInfoName + org.eclipse.sw360.datahandler.common.SW360Utils + java.lang.String printName(org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation) + + + printPackageInfoName + org.eclipse.sw360.datahandler.common.SW360Utils + java.lang.String printName(org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation) + + + + DisplaySPDXDocumentChanges + org.eclipse.sw360.portal.tags.DisplaySPDXDocumentChanges + empty + + actual + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument + true + + + additions + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument + true + + + deletions + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument + true + + + tableClasses + true + java.lang.String + true + + + idPrefix + true + java.lang.String + true + + + + + DisplayDocumentCreationInfoChanges + org.eclipse.sw360.portal.tags.DisplayDocumentCreationInfoChanges + empty + + actual + true + org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation + true + + + additions + true + org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation + true + + + deletions + true + org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation + true + + + tableClasses + true + java.lang.String + true + + + idPrefix + true + java.lang.String + true + + + + + DisplayPackageInfoChanges + org.eclipse.sw360.portal.tags.DisplayPackageInfoChanges + empty + + actual + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation + true + + + additions + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation + true + + + deletions + true + org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation + true + + + tableClasses + true + java.lang.String + true + + + idPrefix + true + java.lang.String + true + + diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/changelogs/elementView.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/changelogs/elementView.jsp index 284cdf4fbd..313eec77ea 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/changelogs/elementView.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/changelogs/elementView.jsp @@ -251,6 +251,8 @@ if(fieldValueOld === null || fieldValueOld === undefined || fieldValueNew === null || fieldValueNew === undefined ) { + removeIndexFields(fieldValueOld); + removeIndexFields(fieldValueNew); jsonStrOld = JSON.stringify(fieldValueOld, undefined, 5).replace(/\\n/g, '\n').replace(/\\r/g, '\r'); jsonStrNew = JSON.stringify(fieldValueNew, undefined, 5).replace(/\\n/g, '\n').replace(/\\r/g, '\r'); } @@ -310,10 +312,13 @@ for (let primaryValue of primaryField) { if(typeof primaryValue === 'object') { let matched = false; + let indexKey = "index"; for(let secondaryValue of secondaryField) { - if(secondaryValue[selector] === primaryValue[selector]) { + if (isEqualObject(secondaryValue, primaryValue, selector, indexKey)) { matched = true; if(differentiateObject) { + delete primaryValue[indexKey]; + delete secondaryValue[indexKey]; diffObject(primaryValue, secondaryValue, primarySpanHightlighter, secondarySpanHighlighter, indentlevel); primaryFieldTmp.push(primaryValue); secondaryFieldTmp.push(secondaryValue); @@ -322,7 +327,8 @@ } } if(!matched) { - let jsonString = JSON.stringify(primaryValue, undefined, 5*indentlevel); + removeIndexFields(primaryValue); + let jsonString = JSON.stringify(primaryValue, undefined, 10*indentlevel); jsonString = jsonString.substring(0, jsonString.length-1) + spaceForClosingBraces + jsonString.substring(jsonString.length-1); primaryFieldTmp.push($($.parseHTML(primarySpanHightlighter)).text(jsonString)[0].outerHTML); } @@ -336,6 +342,33 @@ } } + function isEqualObject(secondaryValue, primaryValue, selector, indexKey) { + if (primaryValue[selector] === secondaryValue[selector] && typeof primaryValue[indexKey] === 'undefined') { + return true; + } + if (primaryValue[indexKey] === secondaryValue[indexKey] && typeof primaryValue[selector] === 'undefined') { + return true; + } + return false; + } + + function removeIndexFields(object) { + if (Array.isArray(object)) { + for (let objectValue of object) { + removeIndexFields(objectValue); + } + } else if (typeof object === 'object') { + for (key in object) { + if (key === 'index') { + delete object[key]; + } + if (typeof object[key] === 'object') { + removeIndexFields(object[key]); + } + } + } + } + function copyFromSourceToDestinationArray(srcArr, destArr) { destArr.length = 0; for (obj of srcArr) { @@ -354,6 +387,11 @@ function highlightObject(fieldValuePrimary, fieldValueSecondary, primarySpanHightlighter, secondarySpanHighlighter, differentiateCommonObject, spaceForClosingBraces, indentlevel) { for(key in fieldValuePrimary) { + if (key === 'index') { + delete fieldValuePrimary[key]; + delete fieldValueSecondary[key]; + continue; + } if(fieldValueSecondary[key] === null || fieldValueSecondary[key] === undefined) { let highlighted = fieldValuePrimary[key]; if(typeof fieldValuePrimary[key] === 'object') { diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/edit.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/edit.jsp index 0aa0a72a30..cd1e136168 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/edit.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/edit.jsp @@ -152,6 +152,8 @@ + + <%@include file="/html/utils/includes/importBomForComponent.jspf" %>
    active show"> @@ -208,7 +210,6 @@ <%@include file="/html/components/includes/vendors/searchVendor.jspf" %> - +<%@include file="/html/utils/includes/requirejs.jspf" %> + +
    +
    + + +
    + <%@include file="/html/components/includes/releases/spdx/includes/editDocumentCreationInformation.jsp" %> + <%@include file="/html/components/includes/releases/spdx/includes/editPackageInformation.jsp" %> + <%@include file="/html/components/includes/releases/spdx/includes/editSnippetInformation.jsp" %> + <%@include file="/html/components/includes/releases/spdx/includes/editOtherLicensingInformationDetected.jsp" %> + <%@include file="/html/components/includes/releases/spdx/includes/editRelationshipsBetweenSPDXElements.jsp"%> + <%@include file="/html/components/includes/releases/spdx/includes/editAnnotations.jsp" %> + + + +
    + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editAnnotations.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editAnnotations.jsp new file mode 100644 index 0000000000..2f924961ab --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editAnnotations.jsp @@ -0,0 +1,102 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + + + +
    12. Annotation Information
    +
    + + +
    +
    +
    + + + + + + + + + +
    +
    + +
    + + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    +
    \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editDocumentCreationInformation.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editDocumentCreationInformation.jsp new file mode 100644 index 0000000000..16178ce4d0 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editDocumentCreationInformation.jsp @@ -0,0 +1,260 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    6. Document Creation Information
    +
    + +
    + + "> +
    +
    +
    + +
    +
    +
    +
    + + "> +
    +
    + +
    +
    +
    +
    + +
    + + "> +
    +
    +
    + +
    +
    +
    +
    +
    + + "> +
    +
    +
    + +
    +
    +
    +
    + + "> +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + + + + + + + + + +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    + +
    +
    + + "> +
    +
    +
    + +
    +
    + + +
    +
    + +
    +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    + + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editOtherLicensingInformationDetected.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editOtherLicensingInformationDetected.jsp new file mode 100644 index 0000000000..002f055e5f --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editOtherLicensingInformationDetected.jsp @@ -0,0 +1,108 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    10. Other Licensing Information Detected
    +
    +
    + + + + + + + + + +
    +
    + +
    + + +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editPackageInformation.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editPackageInformation.jsp new file mode 100644 index 0000000000..944de99fbb --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editPackageInformation.jsp @@ -0,0 +1,498 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    7. Package Information
    +
    +
    + + + + + + + + + +
    +
    + +
    + "> +
    +
    +
    + +
    +
    +
    +
    + +
    + + "> +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + "> +
    +
    +
    + +
    + "> +
    +
    +
    +
    + +
    +
    + + + +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    + + + +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + + + + +
    +
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    + +
    +
    + + + + + + + + + + + + + + + +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + +
    +
    + + + + + + + + +
    + + +
    +
    + + + + +
    +
    + + +
    +
    + + +
    + + +
    +
    + + +
    +
    \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editRelationshipsBetweenSPDXElements.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editRelationshipsBetweenSPDXElements.jsp new file mode 100644 index 0000000000..41127302f9 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editRelationshipsBetweenSPDXElements.jsp @@ -0,0 +1,71 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + +
    11. Relationship between SPDX Elements Information
    +
    + + +
    +
    +
    + + + + + + + + + +
    +
    + +
    + + + +
    +
    +
    +
    + + +
    +
    \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editSnippetInformation.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editSnippetInformation.jsp new file mode 100644 index 0000000000..54e5938039 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editSnippetInformation.jsp @@ -0,0 +1,200 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + + ~ SPDX-License-Identifier: EPL-2.0 +--%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    9. Snippet Information
    +
    +
    + + + + + + + + + +
    +
    + +
    + + +
    +
    +
    + +
    + +
    -
    + +
    +
    +
    +
    + +
    +
    + + + + +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + + +
    +
    + + + + +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/view.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/view.jsp new file mode 100644 index 0000000000..3354179759 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/view.jsp @@ -0,0 +1,1178 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 +--%> + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    6. Document Creation Information
    +
    6.1 SPDX version
    +
    + +
    +
    +
    6.2 Data license
    +
    + +
    +
    +
    6.3 SPDX identifier
    +
    + +
    +
    +
    6.4 Document name
    +
    + +
    +
    +
    6.5 SPDX document namespace
    +
    + +
    +
    +
    6.6 External document references
    +
    +
    +
    Index
    + +
    + +
    +
    External document ID
    +
    + +
    +
    +
    +
    External document
    +
    + +
    +
    +
    +
    Checksum
    +
    + + : + +
    +
    +
    +
    +
    +
    6.7 License list version
    +
    + +
    +
    +
    6.8 Creators
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    6.9 Created
    +
    + +
    +
    +
    6.10 Creator comment
    +
    + +
    +
    +
    6.11 Document comment
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    7. Package Information
    +
    Index
    + +
    +
    7.1 Package name
    +
    + +
    +
    +
    7.2 Package SPDX identifier
    +
    + +
    +
    +
    7.3 Package version
    +
    + +
    +
    +
    7.4 Package file name
    +
    + +
    +
    +
    7.5 Package supplier
    +
    + +
    +
    +
    7.6 Package originator
    +
    + +
    +
    +
    7.7 Package download location
    +
    + +
    +
    +
    7.8 Files analyzed
    +
    + +
    +
    +
    7.9 Package verification code
    +
    +
    +
    Value
    +
    + +
    +
    +
    +
    Excluded files
    +

    + +
    +
    +

    +
    +
    + +
    +
    7.10 Package checksum
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    7.11 Package home page
    +
    + +
    +
    +
    7.12 Source information
    +
    + +
    +
    +
    7.13 Concluded license
    +
    + +
    +
    +
    7.14 All licenses information from files
    +

    + + + +

    +
    +
    7.15 Declared license
    +
    + +
    +
    +
    7.16 Comments on license
    +

    + +

    +
    +
    7.17 Copyright text
    +

    + +

    +
    +
    7.18 Package summary description
    +

    + +

    +
    +
    7.19 Package detailed description
    +

    + +

    +
    +
    7.20 Package comment
    +

    + +

    +
    +
    7.21 External references
    + +
    +
    +
    Index
    + +
    + +
    +
    Category
    +
    + +
    +
    +
    +
    Type
    +
    + +
    +
    +
    +
    Locator
    +
    + +
    +
    +
    +
    7.22 Comment
    +

    + +

    +
    +
    + +
    +
    +
    7.23 Package attribution text
    +

    + +
    +
    +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    9. Snippet Information
    +
    Index
    + +
    +
    9.1 Snippet SPDX identifier
    +
    + +
    +
    +
    9.2 Snippet from file SPDX identifier
    +
    + +
    +
    +
    9.3 & 9.4 Snippet ranges
    +
    + +
    +
    + +
    +
    +
    + +
    +
    ~
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    9.5 Snippet concluded license
    +
    + +
    +
    +
    9.6 License information in snippet
    +

    + +
    +
    +

    +
    +
    9.7 Snippet comments on license
    +

    + +

    +
    +
    9.8 Snippet copyright text
    +

    + +

    +
    +
    9.9 Snippet comment
    +

    + +

    +
    +
    9.10 Snippet name
    +

    + +

    +
    +
    9.11 Snippet attribution text
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    10. Other Licensing Information Detected
    +
    Index
    + +
    +
    10.1 License identifier
    +
    + +
    +
    +
    10.2 Extracted text
    +

    + +

    +
    +
    10.3 License name
    +
    + +
    +
    +
    10.4 License cross reference
    +

    + +
    +
    +

    +
    +
    10.5 License comment
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    11. Relationship between SPDX Elements Information
    +
    Source
    + +
    +
    Index
    + +
    +
    11.1 Relationship
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    11.2 Relationship comment
    +

    + +

    +
    +
    11.1 Relationship
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    11.2 Relationship comment
    +

    + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    12. Annotation Information
    +
    Source
    + +
    +
    Index
    + +
    +
    12.1 Annotator
    +

    + +

    + +
    +
    12.2 Annotation date
    +

    + +

    +
    +
    12.3 Annotation type
    +
    +
    +
    + +
    +
    +
    +
    +
    12.4 SPDX identifier reference
    +
    + +
    +
    +
    12.5 Annotation comment
    +

    + +

    +
    +
    12.1 Annotator
    +

    + +

    + +
    +
    12.2 Annotation date
    +

    + +

    +
    +
    12.3 Annotation type
    +
    +
    +
    + +
    +
    +
    +
    +
    12.4 SPDX identifier reference
    +
    + +
    +
    +
    12.5 Annotation comment
    +

    + +

    +
    + + + + diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/view.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/view.jsp index 5719a478a5..b6092ccd42 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/view.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/view.jsp @@ -172,23 +172,23 @@
    - + + +
    +
    + + +
    +
    +
    (${totalRows})"> (${totalRows})
    @@ -209,7 +209,7 @@ <%--for javascript library loading --%> <%@ include file="/html/utils/includes/requirejs.jspf" %> -<%@ include file="/html/utils/includes/importBom.jspf" %> +<%@ include file="/html/utils/includes/importBomForComponent.jspf" %> \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/documentcreationinfo/merge.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/documentcreationinfo/merge.jsp new file mode 100644 index 0000000000..853fa6df03 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/documentcreationinfo/merge.jsp @@ -0,0 +1,102 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 + --%> +<%@include file="/html/init.jsp"%> +<%-- the following is needed by liferay to display error messages--%> +<%@include file="/html/utils/includes/errorKeyToMessage.jspf"%> + + + + +<%@ page import="com.liferay.portal.kernel.portlet.PortletURLFactoryUtil" %> +<%@ page import="org.eclipse.sw360.datahandler.thrift.moderation.DocumentType" %> +<%@ page import="javax.portlet.PortletRequest" %> +<%@ page import="org.eclipse.sw360.portal.common.PortalConstants" %> + + + + + + + +
    + + + <%@include file="/html/moderation/includes/moderationHeader.jspf"%> + +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/moderation/includes/moderationInfo.jspf"%> +
    +
    +
    + +
    +
    +

    + +

    +
    +
    +
    +

    + +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/utils/includes/requirejs.jspf" %> + <%@include file="/html/components/includes/releases/spdx/view.jsp"%> +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/delete.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/delete.jsp new file mode 100644 index 0000000000..9e7e5a6aec --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/delete.jsp @@ -0,0 +1,96 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 + --%> +<%@include file="/html/init.jsp"%> +<%-- the following is needed by liferay to display error messages--%> +<%@include file="/html/utils/includes/errorKeyToMessage.jspf"%> + + + + +<%@ page import="com.liferay.portal.kernel.portlet.PortletURLFactoryUtil" %> +<%@ page import="org.eclipse.sw360.datahandler.thrift.moderation.DocumentType" %> +<%@ page import="javax.portlet.PortletRequest" %> +<%@ page import="org.eclipse.sw360.portal.common.PortalConstants" %> + + + + + +
    + + + <%@include file="/html/moderation/includes/moderationHeader.jspf"%> + +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/moderation/includes/moderationInfo.jspf"%> +
    +
    +
    + +
    +
    +

    + +

    +
    +
    +
    + The SPDX Document is requested to be deleted. +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + + + <%@include file="/html/utils/includes/requirejs.jspf" %> + <%@include file="/html/components/includes/releases/spdx/view.jsp"%> +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/merge.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/merge.jsp new file mode 100644 index 0000000000..dcdd8457e6 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/merge.jsp @@ -0,0 +1,105 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 + --%> +<%@include file="/html/init.jsp"%> +<%-- the following is needed by liferay to display error messages--%> +<%@include file="/html/utils/includes/errorKeyToMessage.jspf"%> + + + + +<%@ page import="com.liferay.portal.kernel.portlet.PortletURLFactoryUtil" %> +<%@ page import="org.eclipse.sw360.datahandler.thrift.moderation.DocumentType" %> +<%@ page import="javax.portlet.PortletRequest" %> +<%@ page import="org.eclipse.sw360.portal.common.PortalConstants" %> + + + + + + + +
    + + + <%@include file="/html/moderation/includes/moderationHeader.jspf"%> + +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/moderation/includes/moderationInfo.jspf"%> +
    +
    +
    + +
    +
    +

    + +

    +
    +
    +
    +

    + +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + + + <%@include file="/html/utils/includes/requirejs.jspf" %> + <%@include file="/html/components/includes/releases/spdx/view.jsp"%> +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/delete.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/delete.jsp new file mode 100644 index 0000000000..ecd13d4e33 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/delete.jsp @@ -0,0 +1,92 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 + --%> +<%@include file="/html/init.jsp"%> +<%-- the following is needed by liferay to display error messages--%> +<%@include file="/html/utils/includes/errorKeyToMessage.jspf"%> + + + + +<%@ page import="com.liferay.portal.kernel.portlet.PortletURLFactoryUtil" %> +<%@ page import="org.eclipse.sw360.datahandler.thrift.moderation.DocumentType" %> +<%@ page import="javax.portlet.PortletRequest" %> +<%@ page import="org.eclipse.sw360.portal.common.PortalConstants" %> + + + + + +
    + + + <%@include file="/html/moderation/includes/moderationHeader.jspf"%> + +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/moderation/includes/moderationInfo.jspf"%> +
    +
    +
    + +
    +
    +

    + +

    +
    +
    +
    + The SPDX Document is requested to be deleted. +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/utils/includes/requirejs.jspf" %> + <%@include file="/html/components/includes/releases/spdx/view.jsp"%> +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/merge.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/merge.jsp new file mode 100644 index 0000000000..da999d944e --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/merge.jsp @@ -0,0 +1,101 @@ +<%-- + ~ Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + ~ Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + ~ + ~ This program and the accompanying materials are made + ~ available under the terms of the Eclipse Public License 2.0 + ~ which is available at https://www.eclipse.org/legal/epl-2.0/ + ~ + ~ SPDX-License-Identifier: EPL-2.0 + --%> +<%@include file="/html/init.jsp"%> +<%-- the following is needed by liferay to display error messages--%> +<%@include file="/html/utils/includes/errorKeyToMessage.jspf"%> + + + + +<%@ page import="com.liferay.portal.kernel.portlet.PortletURLFactoryUtil" %> +<%@ page import="org.eclipse.sw360.datahandler.thrift.moderation.DocumentType" %> +<%@ page import="javax.portlet.PortletRequest" %> +<%@ page import="org.eclipse.sw360.portal.common.PortalConstants" %> + + + + + + + +
    + + + <%@include file="/html/moderation/includes/moderationHeader.jspf"%> + +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/moderation/includes/moderationInfo.jspf"%> +
    +
    +
    + +
    +
    +

    + +

    +
    +
    +
    +

    + +
    +
    +
    +
    +
    +
    +

    + +

    +
    +
    +
    + <%@include file="/html/utils/includes/requirejs.jspf" %> + <%@include file="/html/components/includes/releases/spdx/view.jsp"%> +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/linkedObligations.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/linkedObligations.jsp index 7449887f31..878a0e7812 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/linkedObligations.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/linkedObligations.jsp @@ -38,7 +38,6 @@ - @@ -115,7 +114,7 @@ AUI().use('liferay-portlet-url', function () { badgeClass="badge badge-danger" - + badgeClass="badge badge-success" diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/importBom.jspf b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/importBom.jspf index 6c89e08532..e3fa1df329 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/importBom.jspf +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/importBom.jspf @@ -39,7 +39,7 @@
    - - +
    @@ -44,7 +44,7 @@ ]); - datatables.create('#usingProjectsTable', { + datatables.create('#${tableId}', { data: result, lengthChange: false, language: { diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/spdxjs.js b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/spdxjs.js new file mode 100644 index 0000000000..7d37c002b4 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/spdxjs.js @@ -0,0 +1,1157 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +define('components/includes/releases/spdxjs', ['jquery',"components/includes/releases/validateLib"] , function($,validateLib) { + function enableSection(section, state) { + if (!state) { + section.find('button').attr('disabled', 'disabled'); + + section.find('select').attr('disabled', 'disabled'); + + section.find('input').attr('disabled', 'disabled'); + + section.find('textarea').attr('disabled', 'disabled'); + + section.find('.spdx-delete-icon-main').css('cursor', 'not-allowed'); + + section.find('.spdx-delete-icon-sub').css('cursor', 'not-allowed'); + } else { + section.find('button').removeAttr('disabled'); + + section.find('select').removeAttr('disabled'); + + section.find('input').removeAttr('disabled'); + + section.find('textarea').removeAttr('disabled'); + + section.find('select').removeAttr('disabled'); + + section.find('.spdx-delete-icon-main').css('cursor', 'pointer'); + + section.find('.spdx-delete-icon-sub').css('cursor', 'pointer'); + } + + section.find('.always-enable').removeAttr('disabled'); + + section.find('.spdx-radio').each(function () { + $(this).parent().parent().find('input[type=text]').attr('disabled', 'true'); + + $(this).parent().parent().find('select').attr('disabled', 'true'); + + $(this).parent().parent().find('textarea').attr('disabled', 'true'); + }); + + section.find('.spdx-add-button-main').removeAttr('disabled'); + } + + function clearSection(section) { + section.find('input[type=text]').val(''); + + section.find('textarea').val(''); + + section.find('select').not('.spdx-select').prop("selectedIndex", 0).change(); + + section.find('input[type=radio]').prop('checked', false); + } + + function deleteMain(deleteBtn) { + if ($(deleteBtn).css('cursor') == 'not-allowed') { + return; + } + + let selectbox = $(deleteBtn).prev('select'); + + selectbox.find('option:selected').remove(); + + if (selectbox.find('option').length == 0) { + selectbox.attr('disabled', 'true'); + + $(deleteBtn).css('cursor', 'not-allowed') + } + + let newItem = selectbox.find('option:selected').val(); + + if (typeof (newItem) == 'undefined') { + section = selectbox.closest('.section'); + + enableSection(section, false); + + clearSection(section); + } else { + selectbox.change(); + } + } + + function deleteSub(deleteBtn) { + if ($(deleteBtn).css('cursor') == 'not-allowed') { + return; + } + + let section = $(deleteBtn).parent().parent(); + + if (section.find('.spdx-delete-icon-sub').length == 1) { + $(deleteBtn).parent().css('display', 'none'); + + $(deleteBtn).addClass('hidden'); + } else { + $(deleteBtn).parent().remove(); + } + } + + function addMain(addBtn) { + let selectbox = $(addBtn).prev().find('select'); + + let newIndex = parseInt(selectbox.find('option').last().val()) + 1; + + if (isNaN(newIndex)) { + newIndex = 1; + } + + selectbox.append(''); + + section = selectbox.closest('.section'); + + enableSection(section, true); + + clearSection(section); + + selectbox.val(newIndex); + } + + function addSub(addBtn) { + if ($(addBtn).prev().css('display') == 'none') { + $(addBtn).prev().css('display', 'flex'); + + $(addBtn).prev().find('[name=delete-snippetRange]').removeClass('hidden'); + + $(addBtn).prev().find('[name=checksum-delete]').removeClass('hidden'); + + clearSection($(addBtn).prev()); + + $(addBtn).prev().find('*').removeAttr('disabled'); + + $(addBtn).prev().find('.spdx-delete-icon-sub').css('cursor', 'pointer'); + + if ($(addBtn).hasClass('spdx-add-button-sub-creator')) { + if ($('#creator-anonymous').is(':checked')) { + $(addBtn).prev().find('.creator-type').val('Tool'); + } else { + $(addBtn).prev().find('.creator-type').val('Organization'); + } + } + } else { + let newItem = $(addBtn).prev().clone(); + + clearSection(newItem) + + newItem.find('*').removeAttr('disabled'); + + newItem.find('.spdx-delete-icon-sub').css('cursor', 'pointer'); + + if ($(addBtn).hasClass('spdx-add-button-sub-creator')) { + if ($('#creator-anonymous').is(':checked')) { + newItem.find('.creator-type').val('Tool'); + } else { + newItem.find('.creator-type').val('Organization'); + } + } + + $(addBtn).before(newItem); + } + } + + function updateRadioButton(button) { + if ($(button).attr('id') == 'FilesAnalyzedFalse' && $(button).is(':checked')) { + $('#verificationCodeValue').attr('disabled', 'true'); + + $('#excludedFiles').attr('disabled', 'true'); + + $('#licenseInfoFromFilesExist').attr('disabled', 'true'); + + $('#licenseInfoFromFilesValue').attr('disabled', 'true'); + + $('#licenseInfoFromFilesNone').attr('disabled', 'true'); + + $('#licenseInfoFromFilesNoAssertion').attr('disabled', 'true'); + + return; + } + + if ($(button).attr('id') == 'FilesAnalyzedTrue' && $(button).is(':checked')) { + $('#verificationCodeValue').removeAttr('disabled'); + + $('#excludedFiles').removeAttr('disabled'); + + $('#licenseInfoFromFilesExist').removeAttr('disabled'); + + $('#licenseInfoFromFilesNone').removeAttr('disabled'); + + $('#licenseInfoFromFilesNoAssertion').removeAttr('disabled'); + + if (!$('#licenseInfoFromFilesNone').is(':checked') && !$('#licenseInfoFromFilesNoAssertion').is(':checked')) { + $('#licenseInfoFromFilesExist').click(); + } + + if ($('#licenseInfoFromFilesExist').is(':checked')) { + $('#licenseInfoFromFilesValue').removeAttr('disabled'); + } + + return; + } + + if (button.val() == 'NONE' || button.val() == 'NOASSERTION') { + button.parent().parent().find('input[type=text]').attr('disabled', 'true'); + + button.parent().parent().find('select').attr('disabled', 'true'); + + button.parent().parent().find('textarea').attr('disabled', 'true'); + } else { + button.parent().parent().find('input[type=text]').removeAttr('disabled'); + + button.parent().parent().find('select').removeAttr('disabled'); + + button.parent().parent().find('textarea').removeAttr('disabled'); + } + } + + function readDocumentCreator() { + let creators = []; + + let index = 0; + + $('[name=creatorRow]').each(function () { + if ($(this).css('display') == 'none') { + return; + } + + if ($(this).find('.creator-type').first().attr('disabled')) { + return; + } + + let creatorType = $(this).find('.creator-type').first().val().trim(); + + let creatorValue = $(this).find('.creator-value').first().val().trim(); + + if (creatorValue != '') { + creators.push({ 'type': creatorType, 'value': creatorValue, 'index': index }); + index += 1; + } + }); + + return creators; + } + + function fillDateTime(datePicker, timePicker, value) { + let timeStamp = Date.parse(value); + + let date = new Date(timeStamp); + + let localTimeStamp = timeStamp - date.getTimezoneOffset(); + + let localDate = new Date(localTimeStamp); + + $(datePicker).val(localDate.getFullYear() + + '-' + (localDate.getMonth() + 1).toString().padStart(2, '0') + + '-' + localDate.getDate().toString().padStart(2, '0')); + + $(timePicker).val(date.getHours().toString().padStart(2, '0') + + ':' + date.getMinutes().toString().padStart(2, '0') + + ':' + date.getSeconds().toString().padStart(2, '0')); + } + + function fillMultiOptionsField(inputTag, value, type = 'text') { + if (type == 'array' && value.length == 1) { + if (value[0].toUpperCase() == 'NONE' || value[0].toUpperCase() == 'NOASSERTION') { + $(inputTag).val(''); + + $(inputTag).parent().parent().find('input[value=' + value[0].toUpperCase() + ']').click(); + + return; + } + } + + if (type != 'array' && (value.toUpperCase() == 'NONE' || value.toUpperCase() == 'NOASSERTION')) { + $(inputTag)[0].selectedIndex = 0; + + $(inputTag).parent().find('input').val(''); + + $(inputTag).parent().find('textarea').val(''); + + $(inputTag).parent().parent().find('input[value=' + value.toUpperCase() + ']').click(); + } else { + switch (type) { + case 'array': + fillArray(inputTag, value); + break; + case 'annotator': + fillAnnotator(inputTag, value); + break; + case 'text': + default: + $(inputTag).val(value); + $(inputTag).prev().click(); + } + + $(inputTag).parent().parent().find('input[value=EXIST]').click(); + } + } + + function fillArray(textarea, value) { + if (Array.isArray(value)) { + $(textarea).val(value.sort().join('\n')); + } else { + $(textarea).val(''); + } + } + + function fillAnnotator(typeTag, value) { + if (value.startsWith('Organization: ')) { + $(typeTag).val('Organization'); + + $(typeTag).next().val(value.substr(14)); + } else if (value.startsWith('Person: ')) { + $(typeTag).val('Person'); + + $(typeTag).next().val(value.substr(8)); + } else if (value.startsWith('Tool: ')) { + $(typeTag).val('Tool'); + + $(typeTag).next().val(value.substr(6)); + } else { + $(typeTag).val('Organization'); + + $(typeTag).next().val(''); + } + } + + function readMultiOptionField(inputTag, type = 'text') { + if ($(inputTag).attr('disabled')) { + if (type == 'array') { + return [$(inputTag).parent().parent().find('[type=radio]:checked').val()]; + } else { + return $(inputTag).parent().parent().find('[type=radio]:checked').val(); + } + } else { + switch (type) { + case 'array': + return readArray(inputTag); + case 'annotator': + return readAnnotator(inputTag); + case 'text': + default: + let result = $(inputTag).val().trim(); + + if (result.toUpperCase() == 'NONE' || result.toUpperCase() == 'NOASSERTION') { + return result.toUpperCase(); + } else { + return result; + } + } + } + } + + function readArray(textarea) { + let result = $(textarea).val().split('\n'); + + for (let i = 0; i < result.length; i++) { + result[i] = result[i].trim(); + } + + result.filter(function(e) { return e !== '' }).sort(); + + if (result.length == 1 && (result[0].toUpperCase() == 'NONE' || result[0].toUpperCase() == 'NOASSERTION')) { + return [result[0].toUpperCase()]; + } + + return result.filter(function(v) { return v !=='' } ); + } + + function readAnnotator(typeTag) { + let val = $(typeTag).parent().parent().find('.spdx-radio:checked').val(); + + if (val != 'EXIST') { + $(typeTag).parent().parent().find('[type=radio]:checked').val(); + } + + if ($(typeTag).next().val().trim() != '') { + val = $(typeTag).val() + ': ' + $(typeTag).next().val().trim(); + } else { + val = ''; + } + + return val; + } + + function readDateTime(datePicker, timePicker) { + if ($(datePicker).val() == '' || $(timePicker).val() == '') { + return ''; + } + + let localDate = new Date($(datePicker).val() + ' ' + $(timePicker).val()); + + return localDate.toISOString().slice(0, -5) + 'Z'; + } + + function fillSelectbox(selectbox, num) { + $(selectbox).find('option').remove(); + + for (let i = 0; i < num; i++) { + $(selectbox).append(''); + } + + if (num > 0) { + $(selectbox).val(1); + } + } + + // --------------------------------- Document Creation --------------------------------- + + function initDocumentCreation(userDisplay) { + if (documentCreationInformationObj['spdxVersion'].startsWith('SPDX-')) { + $('#spdxVersion').val(documentCreationInformationObj['spdxVersion'].substr(5).trim()); + } else { + $('#spdxVersion').val('2.2'); + } + + if (documentCreationInformationObj['dataLicense'] == '') { + $('#dataLicense').val('CC0-1.0'); + } + + if (documentCreationInformationObj['SPDXID'].startsWith('SPDXRef-')) { + $('#spdxIdentifier').val(documentCreationInformationObj['SPDXID'].substr(8).trim()); + } else { + $('#spdxIdentifier').val('DOCUMENT'); + } + + if (documentCreationInformationObj.externalDocumentRefs.length == 0) { + enableSection($('.section-external-doc-ref'), false); + } else { + fillSelectbox('#externalDocumentRefs', documentCreationInformationObj.externalDocumentRefs.length); + + fillExternalDocRef(0); + } + + if (documentCreationInformationObj.creator.length == 0) { + $('.spdx-add-button-sub-creator').first().click(); + $('.creator-type').last().val('Person'); + $('.creator-value').last().val(userDisplay); + } else { + for (let i = 0; i < documentCreationInformationObj.creator.length; i++) { + addSub($('.spdx-add-button-sub-creator').first()); + $('.creator-type').last().val(documentCreationInformationObj.creator[i].type); + $('.creator-value').last().val(documentCreationInformationObj.creator[i].value); + } + } + + $('[name=delete-spdx-creator]').bind('click', function() { + deleteSub($(this)); + }); + + if (documentCreationInformationObj.created == '') { + fillDateTime('#createdDate', '#createdTime', (new Date().toISOString())); + } else { + fillDateTime('#createdDate', '#createdTime', documentCreationInformationObj.created); + } + + $('#creatorComment').val(documentCreationInformationObj['creatorComment'].trim()); + $('#documentComment').val(documentCreationInformationObj['documentComment'].trim()); + } + + function storeDocumentCreation() { + if ($('#spdxVersion').val().trim() == '') { + documentCreationInformationObj['spdxVersion'] = 'SPDX-2.2'; + } else { + documentCreationInformationObj['spdxVersion'] = 'SPDX-' + $('#spdxVersion').val().trim(); + } + + if ($('#dataLicense').val().trim() == '') { + documentCreationInformationObj['dataLicense'] = 'CC0-1.0'; + } else { + documentCreationInformationObj['dataLicense'] = $('#dataLicense').val().trim(); + } + + if ($('#spdxIdentifier').val().trim() == '') { + documentCreationInformationObj['SPDXID'] = 'SPDXRef-DOCUMENT'; + } else { + documentCreationInformationObj['SPDXID'] = 'SPDXRef-' + $('#spdxIdentifier').val().trim(); + } + + documentCreationInformationObj['name'] = $('#documentName').val().trim(); + + documentCreationInformationObj['documentNamespace'] = $('#documentNamespace').val().trim(); + + documentCreationInformationObj['licenseListVersion'] = $('#licenseListVersion').val().trim(); + + documentCreationInformationObj.creator = readDocumentCreator(); + + documentCreationInformationObj['created'] = readDateTime('#createdDate', '#createdTime'); + + documentCreationInformationObj['creatorComment'] = $('#creatorComment').val().trim(); + + documentCreationInformationObj['documentComment'] = $('#documentComment').val().trim(); + + if (documentCreationInformationObj['created'] == '') { + documentCreationInformationObj['created'] = (new Date()).toISOString(); + } + } + + // --------------------------------- External Document Reference --------------------------------- + + function fillExternalDocRef(index) { + index = $('#externalDocumentRefs')[0].selectedIndex; + + let obj = documentCreationInformationObj.externalDocumentRefs[index]; + + $('#externalDocumentId').val(obj['externalDocumentId']); + + $('#externalDocument').val(obj['spdxDocument']); + + $('#checksumAlgorithm').val(obj['checksum']['algorithm']); + + $('#checksumValue').val(obj['checksum']['checksumValue']); + } + + function storeExternalDocRef(index) { + if (index < 0 || index > documentCreationInformationObj.externalDocumentRefs.length - 1) { + return; + } + + let obj = documentCreationInformationObj.externalDocumentRefs[index]; + + obj['externalDocumentId'] = $('#externalDocumentId').val().trim(); + + obj['spdxDocument'] = $('#externalDocument').val().trim(); + + let algorithm = $('#checksumAlgorithm').val().trim(); + + let checksumValue = $('#checksumValue').val().trim(); + + if (algorithm == '' || checksumValue == '') { + obj['checksum']['algorithm'] = ''; + obj['checksum']['checksumValue'] = ''; + } else { + obj['checksum']['algorithm'] = algorithm; + obj['checksum']['checksumValue'] = checksumValue; + } + } + + // --------------------------------- Package Information --------------------------------- + + function initPackageInfo() { + if (packagesInformationObj.length == 0) { + enableSection($('.section-package'), false); + } else { + fillSelectbox('#selectPackage', packagesInformationObj.length); + + fillPackage(0); + } + } + + function fillPackage(index) { + const packageInformationObj = packagesInformationObj[index] + + $('#packageName').val(packageInformationObj['name']); + + if (packageInformationObj.SPDXID.startsWith('SPDXRef-')) { + $('#packageSPDXId').val(packageInformationObj.SPDXID.substr(8)); + } else { + $('#packageSPDXId').val('Package-' + packageInformationObj['name']); + } + + $('#versionInfo').val(packageInformationObj['versionInfo']); + $('#packageFileName').val(packageInformationObj['packageFileName']); + $('#sourceInfo').val(packageInformationObj['sourceInfo']); + $('#licenseComments').val(packageInformationObj['licenseComments']); + $('#summary').val(packageInformationObj['summary']); + $('#description').val(packageInformationObj['description']); + $('#spdxPackageComment').val(packageInformationObj['packageComment']); + + + + fillMultiOptionsField('#supplierType', packageInformationObj.supplier, 'annotator'); + + fillMultiOptionsField('#originatorType', packageInformationObj.originator, 'annotator'); + + fillMultiOptionsField('#downloadLocationValue', packageInformationObj.downloadLocation); + + if (packageInformationObj.filesAnalyzed) { + $('#FilesAnalyzedTrue').click(); + + $('#verificationCodeValue').val(packageInformationObj.packageVerificationCode.value); + + fillArray('#excludedFiles', packageInformationObj.packageVerificationCode.excludedFiles); + } else { + $('#FilesAnalyzedFalse').click(); + + $('#verificationCodeValue').val(''); + + $('#excludedFiles').val(''); + } + + if ($('[name=checksum-delete].hidden').length == 0) { + const checksumsNum = $('[name=checksumRow]').length; + + for (let i = 0; i < checksumsNum; i++) { + if (i == 0) { + $($('[name=checksumRow]')[i]).css('display', 'none'); + + $($('[name=checksumRow]')[i]).find('[name=checksum-delete]').addClass('hidden'); + + clearSection($($('[name=checksumRow]')[i])); + } else { + $('[name=checksumRow]').last().remove(); + } + } + } + + for (let i = 0; i < packageInformationObj.checksums.length; i++) { + addSub($('.spdx-add-button-sub-checksum').first()); + + $('.checksum-delete').last().bind('click', function() { + deleteSub($(this)); + }); + + let algorithm = packageInformationObj.checksums[i].algorithm; + + let checksumValue = packageInformationObj.checksums[i].checksumValue; + + $('.checksum-algorithm').last().val(algorithm); + + $('.checksum-value').last().val(checksumValue); + } + + $('.checksum-algorithm, .checksum-value').bind('change keyup', function() { + let selectedPackage = $('#selectPackage')[0].selectedIndex; + if ($(this).is(":focus")) { + //storePackageInfo(packageInformationObj.index); + storePackageInfo(selectedPackage); + } + }); + + $('.checksum-delete').bind('click', function() { + let selectedPackage = $('#selectPackage')[0].selectedIndex; + deleteSub($(this)); + storePackageInfo(selectedPackage); + //storePackageInfo(packageInformationObj.index); + }); + + fillMultiOptionsField('#packageHomepageValue', packageInformationObj.homepage); + + fillMultiOptionsField('#licenseConcludedValue', packageInformationObj.licenseConcluded); + + fillMultiOptionsField('#licenseInfoFromFilesValue', packageInformationObj.licenseInfoFromFiles, 'array'); + + fillMultiOptionsField('#licenseDeclaredValue', packageInformationObj.licenseDeclared); + + fillMultiOptionsField('#copyrightTextValue', packageInformationObj.copyrightText); + + if (packageInformationObj.externalRefs.length == 0) { + enableSection($('.section-external-ref'), false); + $('#externalReferences').empty(); + } else { + fillSelectbox('#externalReferences', packageInformationObj.externalRefs.length); + + fillExternalRef(packageInformationObj, 0); + } + + fillArray('#spdxPackageAttributionText', packageInformationObj.attributionText); + + } + + + function storePackageInfo(packageIndex) { + let packageInformationObj = packagesInformationObj[packageIndex]; + packageInformationObj['name'] = $('#packageName').val().trim(); + + if ($('#packageSPDXId').val().trim() == '') { + packageInformationObj['SPDXID'] = 'SPDXRef-Package-' + packageInformationObj['name']; + } else { + packageInformationObj['SPDXID'] = 'SPDXRef-' + $('#packageSPDXId').val().trim(); + } + + packageInformationObj['versionInfo'] = $('#versionInfo').val().trim(); + + packageInformationObj['packageFileName'] = $('#packageFileName').val().trim(); + + packageInformationObj['supplier'] = readMultiOptionField('#supplierType', 'annotator'); + + packageInformationObj['originator'] = readMultiOptionField('#originatorType', 'annotator'); + + packageInformationObj['downloadLocation'] = readMultiOptionField('#downloadLocationValue'); + + packageInformationObj['filesAnalyzed'] = $('[name=_sw360_portlet_components_FILES_ANALYZED]:checked').val(); + + if (packageInformationObj['filesAnalyzed'] == 'true') { + packageInformationObj['packageVerificationCode']['value'] = $('#verificationCodeValue').val().trim(); + + packageInformationObj['packageVerificationCode']['excludedFiles'] = readArray('#excludedFiles'); + } else { + packageInformationObj['packageVerificationCode']['value'] = ''; + + packageInformationObj['packageVerificationCode']['excludedFiles'] = ''; + } + + packageInformationObj['checksums'] = []; + + let index = 0; + + $('[name=checksumRow]').each(function() { + let algorithm = $(this).find('.checksum-algorithm').first().val().trim(); + + let checksumValue = $(this).find('.checksum-value').first().val().trim(); + + if (algorithm !='' && checksumValue != '') { + packageInformationObj['checksums'].push({ 'algorithm': algorithm, 'checksumValue': checksumValue, 'index': index }); + index += 1; + } + }); + + packageInformationObj['homepage'] = readMultiOptionField('#packageHomepageValue'); + + packageInformationObj['sourceInfo'] = $('#sourceInfo').val().trim(); + + packageInformationObj['licenseConcluded'] = readMultiOptionField('#licenseConcludedValue'); + + if (packageInformationObj['filesAnalyzed'] == 'true') { + packageInformationObj['licenseInfoFromFiles'] = readMultiOptionField('#licenseInfoFromFilesValue', 'array'); + } else { + packageInformationObj['licenseInfoFromFiles'] = []; + } + + packageInformationObj['licenseDeclared'] = readMultiOptionField('#licenseDeclaredValue'); + + packageInformationObj['licenseComments'] = $('#licenseComments').val().trim(); + + packageInformationObj['copyrightText'] = readMultiOptionField('#copyrightTextValue'); + + packageInformationObj['summary'] = $('#summary').val().trim(); + + packageInformationObj['description'] = $('#description').val().trim(); + + packageInformationObj['packageComment'] = $('#spdxPackageComment').val().trim(); + + packageInformationObj['attributionText'] = readMultiOptionField('#spdxPackageAttributionText', 'array'); + } + + // --------------------------------- External Reference --------------------------------- + + function fillExternalRef(packageInformationObj, index) { + let obj = packageInformationObj.externalRefs[index]; + $('#externalReferences').removeAttr('disabled'); + + $('#referenceCategory').val(obj['referenceCategory']); + + $('#referenceCategory').change(); + $('#referenceCategory').removeAttr('disabled'); + + if (obj['referenceCategory'] == 'SECURITY' || obj['referenceCategory'] == 'PACKAGE-MANAGER') { + $('#referenceType-1').val(obj['referenceType']); + $('#referenceType-1').removeAttr('disabled'); + + } else { + $('#referenceType-2').val(obj['referenceType']); + $('#referenceType-2').removeAttr('disabled'); + + } + + $('#externalReferencesLocator').val(obj['referenceLocator']); + $('#externalReferencesLocator').removeAttr('disabled'); + + + $('#externalReferencesComment').val(obj['comment']); + $('#externalReferencesComment').removeAttr('disabled'); + } + + function storeExternalRef(packageInformationObj, index) { + if (index < 0 || index > packageInformationObj.externalRefs.length - 1) { + return; + } + + let obj = packageInformationObj.externalRefs[index]; + + obj['referenceCategory'] = $('#referenceCategory').val().trim(); + + if (obj['referenceCategory'] == 'SECURITY' || obj['referenceCategory'] == 'PACKAGE-MANAGER') { + obj['referenceType'] = $('#referenceType-1').val().trim(); + } else { + obj['referenceType'] = $('#referenceType-2').val().trim(); + } + + obj['referenceLocator'] = $('#externalReferencesLocator').val().trim(); + + obj['comment'] = $('#externalReferencesComment').val().trim(); + } + + // --------------------------------- Snippet Information --------------------------------- + + function initSnippetInfo() { + if (spdxDocumentObj.snippets.length == 0) { + enableSection($('.section-snippet'), false); + } else { + fillSelectbox('#selectSnippet', spdxDocumentObj.snippets.length); + + fillSnippet(0); + } + } + + function fillSnippet(index) { + const obj = spdxDocumentObj.snippets[index]; + + if (obj['SPDXID'].startsWith('SPDXRef-')) { + $('#snippetSpdxIdentifier').val(obj['SPDXID'].substr(8)); + } else { + $('#snippetSpdxIdentifier').val('Snippet-' + obj['name']); + } + + if (obj['snippetFromFile'].startsWith('SPDXRef-')) { + $('#snippetFromFile').val('SPDXRef'); + + $('#snippetFromFileValue').val(obj['snippetFromFile'].substr(8)); + } else if (obj['snippetFromFile'].startsWith('DocumentRef-')) { + $('#snippetFromFile').val('DocumentRef'); + + $('#snippetFromFileValue').val(obj['snippetFromFile'].substr(12)); + } else { + $('#snippetFromFile').val('SPDXRef'); + + $('#snippetFromFileValue').val(''); + } + + if ($('[name=delete-snippetRange].hidden').length == 0) { + const rangesNum = $('[name=snippetRange]').length; + + for (let i = 0; i < rangesNum; i++) { + if (i == 0) { + $($('[name=snippetRange]')[i]).css('display', 'none'); + + $($('[name=snippetRange]')[i]).find('[name=delete-snippetRange]').addClass('hidden'); + + clearSection($($('[name=snippetRange]')[i])); + } else { + $('[name=snippetRange]').last().remove(); + } + } + } + + for (let i = 0; i < obj.snippetRanges.length; i++) { + addSub('#addNewRange'); + + $('.range-type').last().val(obj.snippetRanges[i].rangeType); + + $('.start-pointer').last().val(obj.snippetRanges[i].startPointer); + + $('.end-pointer').last().val(obj.snippetRanges[i].endPointer); + + $('.reference').last().val(obj.snippetRanges[i].reference); + } + + $('.range-type, .start-pointer, .end-pointer, .reference').bind('change keyup', function() { + if ($(this).is(":focus")) { + storeSnippet(); + } + }); + + $('[name=delete-snippetRange]').bind('click', function() { + deleteSub($(this)); + + storeSnippet(); + }); + + fillMultiOptionsField('#spdxConcludedLicenseValue', obj.licenseConcluded); + + fillMultiOptionsField('#licenseInfoInFileValue', obj.licenseInfoInSnippets, 'array'); + + $('#snippetLicenseComments').val(obj.licenseComments); + + fillMultiOptionsField('#copyrightTextValueSnippet', obj.copyrightText); + + $('#snippetComment').val(obj.comment); + + $('#snippetName').val(obj.name); + + $('#snippetAttributionText').val(obj.snippetAttributionText); + } + + function storeSnippet(index) { + if (typeof(index) == 'undefined') { + index = $('#selectSnippet')[0].selectedIndex; + } + + if (index < 0 || index > spdxDocumentObj.snippets - 1) { + return; + } + + let obj = spdxDocumentObj.snippets[index]; + + if ($('#snippetSpdxIdentifier').val().trim() != '') { + obj['SPDXID'] = 'SPDXRef-' + $('#snippetSpdxIdentifier').val().trim(); + } else { + obj['SPDXID'] = 'SPDXRef-Snippet-' + $('#snippetName').val().trim(); + } + + if ($('#snippetFromFileValue').val().trim() != '') { + obj['snippetFromFile'] = $('#snippetFromFile').val() + '-' + $('#snippetFromFileValue').val().trim(); + } else { + obj['snippetFromFile'] = ''; + } + + obj['snippetRanges'] = []; + + if ($('[name=snippetRange]').first().css('display') != 'none') { + obj['snippetRanges'] = []; + + let index = 0; + + $('[name=snippetRange]').each(function() { + let range = {'rangeType': '', 'startPointer': '', 'endPointer': '', 'reference': ''}; + + range['rangeType'] = $(this).find('.range-type').first().val().trim(); + + range['startPointer'] = $(this).find('.start-pointer').first().val().trim(); + + range['endPointer'] = $(this).find('.end-pointer').first().val().trim(); + + range['reference'] = $(this).find('.reference').first().val().trim(); + + range['index'] = index; + + index += 1; + + if (range['startPointer'] != '' && range['endPointer'] != '' && range['reference'] != '') { + obj['snippetRanges'].push(range); + } + }) + } + + obj['licenseConcluded'] = readMultiOptionField('#spdxConcludedLicenseValue'); + + obj['licenseInfoInSnippets'] = readMultiOptionField('#licenseInfoInFileValue', 'array'); + + obj['licenseComments'] = $('#snippetLicenseComments').val().trim(); + + obj['copyrightText'] = readMultiOptionField('#copyrightTextValueSnippet'); + + obj['comment'] = $('#snippetComment').val().trim(); + + obj['name'] = $('#snippetName').val().trim(); + + obj['snippetAttributionText'] = $('#snippetAttributionText').val().trim(); + } + + // --------------------------------- Other Licensing --------------------------------- + + function initOtherLicensing() { + if (spdxDocumentObj.otherLicensingInformationDetecteds.length == 0) { + enableSection($('.section-other-licensing'), false); + } else { + fillSelectbox('#selectOtherLicensing', spdxDocumentObj.otherLicensingInformationDetecteds.length); + + fillOtherLicensing(0); + } + } + + function fillOtherLicensing(index) { + let obj = spdxDocumentObj.otherLicensingInformationDetecteds[index]; + + if (obj.licenseId.startsWith('LicenseRef-')) { + $('#licenseId').val(obj.licenseId.substr(11)); + } else { + $('#licenseId').val(obj.licenseName); + } + + $('#extractedText').val(obj.extractedText); + + fillMultiOptionsField('#licenseName', obj.licenseName); + + fillArray('#licenseCrossRefs', obj.licenseCrossRefs); + + $('#licenseCommentOnOtherLicensing').val(obj.licenseComment); + } + + function storeOtherLicensing(index) { + if (index < 0 || index > spdxDocumentObj.otherLicensingInformationDetecteds - 1) { + return; + } + + let obj = spdxDocumentObj.otherLicensingInformationDetecteds[index]; + + if ($('#licenseId').val().trim() != '') { + obj['licenseId'] = 'LicenseRef-' + $('#licenseId').val().trim(); + } else { + obj['licenseId'] = 'LicenseRef-' + readMultiOptionField('#licenseName'); + } + + obj['extractedText'] = $('#extractedText').val().trim(); + + obj['licenseName'] = readMultiOptionField('#licenseName'); + + obj['licenseCrossRefs'] = readArray('#licenseCrossRefs'); + + obj['licenseComment'] = $('#licenseCommentOnOtherLicensing').val().trim(); + } + + // --------------------------------- Relationship --------------------------------- + function getRelationshipsSource() { + if ($('#selectRelationshipSource').val() == 'Package') { + return packagesInformationObj[0].relationships; + } + + return spdxDocumentObj.relationships; + } + + + function initRelationships() { + let source = getRelationshipsSource(); + if (source.length == 0) { + enableSection($('.section-relationship'), false); + } else { + fillSelectbox('#selectRelationship', source.length); + + fillRelationship(source, 0); + } + } + + function fillRelationship(sourceRelationship, index) { + let obj = sourceRelationship[index]; + + $('#spdxElement').val(obj.spdxElementId); + + $('#relationshipType').val(obj.relationshipType.toUpperCase()); + + $('#relatedSPDXElement').val(obj.relatedSpdxElement); + + $('#relationshipComment').val(obj.relationshipComment); + } + + function storeRelationship(index) { + let source = getRelationshipsSource() + if (index < 0 || index > source - 1) { + return; + } + + let obj = source[index]; + + obj['spdxElementId'] = $('#spdxElement').val().trim(); + + obj['relationshipType'] = $('#relationshipType').val().toUpperCase().trim(); + + obj['relatedSpdxElement'] = $('#relatedSPDXElement').val().trim(); + + obj['relationshipComment'] = $('#relationshipComment').val().trim(); + } + + // --------------------------------- Annotation --------------------------------- + + function getAnnotationsSource() { + if ($('#selectAnnotationSource').val() == 'Package') { + return packagesInformationObj[0].annotations; + } + + return spdxDocumentObj.annotations; + } + + function initAnnotations() { + let source = getAnnotationsSource(); + + if (source.length == 0) { + enableSection($('.section-annotation'), false); + + $('#selectAnnotation').find('option').remove(); + } else { + enableSection($('.section-annotation'), true); + + fillSelectbox('#selectAnnotation', source.length); + + fillAnnotation(source, 0); + } + } + + function fillAnnotation(source, index) { + let obj = source[index]; + + fillAnnotator('#annotatorType', obj['annotator']); + + fillDateTime('#annotationCreatedDate', '#annotationCreatedTime', obj['annotationDate']); + + $('#annotationType').val(obj['annotationType']); + + $('#spdxIdRef').val(obj['spdxIdRef']); + + $('#annotationComment').val(obj['annotationComment']); + } + + function storeAnnotation(index) { + let source = getAnnotationsSource(); + + if (index < 0 || index > source.length - 1) { + return; + } + + let obj = source[index]; + + if ($('#annotatorValue').val().trim() != '') { + obj['annotator'] = $('#annotatorType').val() + ': ' + $('#annotatorValue').val().trim(); + } else { + obj['annotator'] = ''; + } + + obj['annotationDate'] = readDateTime('#annotationCreatedDate', '#annotationCreatedTime'); + + obj['annotationType'] = $('#annotationType').val().trim(); + + obj['spdxIdRef'] = $('#spdxIdRef').val().trim(); + + obj['annotationComment'] = $('#annotationComment').val().trim(); + } + + + return { + addMain: addMain, + addSub: addSub, + deleteMain: deleteMain, + deleteSub: deleteSub, + + updateRadioButton: updateRadioButton, + + initDocumentCreation: initDocumentCreation, + storeDocumentCreation: storeDocumentCreation, + + readDocumentCreator: readDocumentCreator, + + fillExternalDocRef: fillExternalDocRef, + storeExternalDocRef: storeExternalDocRef, + + initPackageInfo: initPackageInfo, + fillPackage: fillPackage, + storePackageInfo: storePackageInfo, + + fillExternalRef: fillExternalRef, + storeExternalRef: storeExternalRef, + + initSnippetInfo: initSnippetInfo, + fillSnippet: fillSnippet, + storeSnippet: storeSnippet, + + initOtherLicensing: initOtherLicensing, + fillOtherLicensing: fillOtherLicensing, + storeOtherLicensing: storeOtherLicensing, + + getRelationshipsSource: getRelationshipsSource, + initRelationships: initRelationships, + fillRelationship: fillRelationship, + storeRelationship: storeRelationship, + + getAnnotationsSource: getAnnotationsSource, + initAnnotations: initAnnotations, + fillAnnotation: fillAnnotation, + storeAnnotation: storeAnnotation + }; +}); diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/validateLib.js b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/validateLib.js new file mode 100644 index 0000000000..8e6a955951 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/validateLib.js @@ -0,0 +1,254 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +define('components/includes/releases/validateLib', ['jquery'], function ($) { + var errors = []; + var totalErrors = 0; + var formId = ''; + + const numRegex = /^[-+]?\d*$/; + const urlRegex = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/; + const downloadUrlRegex = /(?:git|ssh|https?|ftp|git@[-\w.]+):(\/\/)?(.*?)(\.git)?(\/?|\#[-\d\w._]+?)$/; + + function regex(val, params) { + if (!required(val)) { + return true; + } + var regexText = new RegExp(params); + if (val.match(regexText) != null) { + return true; + } else { + return false; + } + } + + function required(val) { + if ((val == null) || (val == '')) { + return false; + } else { + return true; + } + } + + function integer(val, params) { + if (isNaN(val)) { + return false; + } + + var x = parseFloat(val); + + return (x | 0) === x; + } + + function max(val, params) { + if (val.match(numRegex) == null) { + return true; + } + + if (isNaN(parseInt(val)) || isNaN(parseInt(params))) { + return true; + } + + return parseInt(val) <= parseInt(params); + } + + function min(val, params) { + if (val.match(numRegex) == null) { + return true; + } + + if (isNaN(parseInt(val)) || isNaN(parseInt(params))) { + return true; + } + + return parseInt(val) >= parseInt(params); + } + + function isUrl(val, params) { + if (!required(val)) { + return true; + } + if (val.match(urlRegex)) { + return true; + } else { + return false; + } + } + + function isDownloadUrl(val, params) { + if (!required(val)) { + return true; + } + if (val.match(downloadUrlRegex)) { + return true; + } else { + return false; + } + } + + function getElementVal(element) { + if ($(element).is('input')) { // Textbox, checkbox + var type = $(element).attr('type'); + + switch (type) { + case 'text': + return $(element).val(); + break; + + case 'checkbox': + return $(element).is(':checked'); + break; + + case 'radio': + var name = $(element).attr('name'); + var all_radio_button = document.getElementsByName(name); + for (radio_button in all_radio_button) { + if ($(radio_button).is(':checked')) { + return 'checked'; + } + } + return null; + break; + case 'date': + return $(element).val(); + break; + case 'time': + return $(element).val(); + break; + default: + return undefined; + break; + } + } + + if ($(element).is('select')) { // Selectbox + return $(element).val(); + } + + if ($(element).is('textarea')) { // Textarea + return $(element).val(); + } + + return undefined; + } + + function setFormId(val) { + formId = val; + } + + function validate() { + errors = []; + totalErrors = 0; + + const elements = $('#' + formId).find('.needs-validation'); + + for (var i = 0; i < elements.length; i++) { + const element = elements[i]; + if (typeof $(element).attr('disabled') === 'undefined') { + const elementId = String($(element).attr('id')); + const elementErrors = validateElement(element); + + errors.push({ + id: elementId, + rules: elementErrors + }); + + totalErrors += elementErrors.length; + } + } + } + + function allValid() { + return totalErrors == 0; + } + + function validateElement(element) { + var errors = []; + // var elementRule = $(element).attr('rule'); + if (typeof $(element).attr('rule') === 'undefined' || $(element).attr('rule').length == 0) { + return errors; + } + + var val = getElementVal($(element)); + + var valdationRules = $(element).attr('rule').split('|'); + + valdationRules.forEach(rule => { + var ruleName = rule.split(':')[0]; + var params = rule.split(':')[1]; + + if (!eval(ruleName)(val, params)) { + errors.push(ruleName); + } + }); + return errors; + } + + function showAllErrors() { + hideAllErrors(); + + if (allValid()) { + return; + } + + $('#' + formId).addClass('was-validated'); + + errors.forEach(error => { + showError(error.id, error.rules); + }) + } + + function showError(elementId, rules) { + try { + if (rules.length == 0) { + $('#' + elementId)[0].setCustomValidity(''); + return; + } + + $('#' + elementId)[0].setCustomValidity('error'); + } catch { + console.log('Cannot show error'); + } + + rules.forEach(rule => { + $('#' + elementId + '-error-messages').find("[rule='" + rule + "']").addClass('d-block'); + }) + } + + function hideAllErrors() { + $('#' + formId).removeClass('was-validated'); + const elements = $('#' + formId).find('.needs-validation'); + + for (var i = 0; i < elements.length; i++) { + $(elements[i])[0].setCustomValidity(''); + $('.invalid-feedback').css('display', 'none'); + $('.invalid-feedback').removeClass('d-block'); + } + } + + function addError(elementId, elementErrors) { + errors.push({ + id: elementId, + rules: elementErrors + }); + + totalErrors += elementErrors.length; + } + + return { + setFormId: setFormId, + validate: validate, + allValid: allValid, + addError: addError, + showAllErrors: showAllErrors, + hideAllErrors: hideAllErrors + } +}); \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/utils/array.js b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/utils/array.js new file mode 100644 index 0000000000..ea4dab22a2 --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/js/utils/array.js @@ -0,0 +1,34 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +function dynamicSort(property, type) { + var sortOrder = 1; + + if(property[0] === "-") { + sortOrder = -1; + + property = property.substr(1); + } + + return function (a,b) { + var result; + + switch (type) { + case 'int': + result = (parseInt(a[property]) < parseInt(b[property])) ? -1 : (parseInt(a[property]) > (b[property])) ? 1 : 0; + break; + case 'string': + default: + result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; + } + + return result * sortOrder; + } +} \ No newline at end of file diff --git a/frontend/sw360-portlet/src/main/resources/content/Language.properties b/frontend/sw360-portlet/src/main/resources/content/Language.properties index f8e270be34..31e590d03f 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language.properties @@ -668,7 +668,7 @@ import=Import import.export=Import & Export import.failed=Import failed. import.projects=Import Projects -import.spdx.bom=Import SPDX BOM +import.spdx.bom=Import SBOM import.spdx.information=Import SPDX Information import.spdx.licenses=Import SPDX licenses incorrect=Incorrect @@ -1515,6 +1515,29 @@ object=Object import.obligation.element=Import Obligation Element input=Input an.obligation.with.the.same.name.already.exists=An Obligation with the same name already exists. +## spdx multi language +this.field.must.be.not.empty=This field must be not empty! +invalid.format=Invalid format! +spdx.document=SPDX Document +enter.data.license=Enter Data License +enter.spdx.document.name=Enter SPDX Document Name +enter.spdx.document.namespace=Enter SPDX Document Namespace +changes.in.external.document.references=Changes in External Document References +changes.in.creator=Changes in Creator +changes.in.checksum=Changes in Checksum +changes.in.annotaions.information=Changes in Annotations Information +changes.in.external.references=Changes in External References +changes.in.package.verification.code=Changes in Package Verification Code +changes.in.snippets.information=Changes in Snippets Information +changes.in.relationship.information=Changes in Relationship Information +changes.in.other.licensing.information.detecteds=Changes in Other Licensing Information Detecteds +current.package.information=Current Package Information +current.spdxdocument=Current SPDX Document +current.document.creation.information=Current Document Creation Information +export.sbom=Export SBOM +export.sbom.have.some.warning=Export SBOM have some warning +export.sbom.have.some.error=Export SBOM have some error +no.warning.error.export.sbom=No warning/error export sbom obligation.change.log.is.unavailable.because.obligation.does.not.exist=Obligation Change Log is unavailable because Obligation does not exist. excel.report.generation.has.started.we.will.send.you.an.email.with.download.link.once.completed=Excel report generation has started. We will send you an email with download link once completed. ## Refer to http://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/ and add your datatables language diff --git a/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties b/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties index bec4ae6da9..c6f7558652 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties @@ -668,7 +668,7 @@ import=インポート import.export=インポート& エクスポート import.failed=インポートに失敗しました。 import.projects=プロジェクトのインポート -import.spdx.bom=SPDX BOMのインポート +import.spdx.bom=SBOMのインポート import.spdx.information=SPDX情報のインポート import.spdx.licenses=SPDXライセンスのインポート incorrect=間違い diff --git a/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties b/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties index a9c2232365..febc83c1da 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties @@ -672,7 +672,7 @@ import=Nhập import.export=Nhập và xuất import.failed=Nhập thất bại. import.projects=Nhập các dự án -import.spdx.bom=Nhập SPDX BOM +import.spdx.bom=Nhập SBOM import.spdx.information=Nhập thông tin SPDX import.spdx.licenses=Nhập giấy phép SPDX incorrect=Sai @@ -1521,6 +1521,14 @@ import.obligation.element=Nhập nghĩa vụ thành phần input=Nhập an.obligation.with.the.same.name.already.exists=Nghĩa vụ có cùng tên đã tồn tại. obligation.change.log.is.unavailable.because.obligation.does.not.exist=Không xem được lịch sử thay đổi vì Obligation này không tồn tại. +excel.report.generation.has.started.we.will.send.you.an.email.with.download.link.once.completed=Excel report generation has started. We will send you an email with download link once completed. +export.sbom=Xuất SBOM +export.sbom.have.some.warning=Xuất SBOM có một số cảnh báo +export.sbom.have.some.error=Xuất SBOM có một số lỗi +no.warning.error.export.sbom=Không có lỗi/cảnh báo khi xuất +obligation.change.log.is.unavailable.because.obligation.does.not.exist=Không xem được lịch sử thay đổi vì Obligation này không tồn tại. + + excel.report.generation.has.started.we.will.send.you.an.email.with.download.link.once.completed=Excel report generation has started. We will send you an email with download link once completed. ## Refer to http://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/ and add your datatables language diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/DatabaseSettings.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/DatabaseSettings.java index a8893a1e65..c1ba455889 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/DatabaseSettings.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/DatabaseSettings.java @@ -43,6 +43,7 @@ public class DatabaseSettings { public static final String COUCH_DB_CONFIG; public static final String COUCH_DB_USERS; public static final String COUCH_DB_VM; + public static final String COUCH_DB_SPDX; public static final int LUCENE_SEARCH_LIMIT; public static final boolean LUCENE_LEADING_WILDCARD; @@ -63,6 +64,7 @@ public class DatabaseSettings { COUCH_DB_CONFIG = props.getProperty("couchdb.config", "sw360config"); COUCH_DB_USERS = props.getProperty("couchdb.usersdb", "sw360users"); COUCH_DB_VM = props.getProperty("couchdb.vulnerability_management", "sw360vm"); + COUCH_DB_SPDX = props.getProperty("couchdb.sw360spdx", "sw360spdx"); LUCENE_SEARCH_LIMIT = Integer.parseInt(props.getProperty("lucenesearch.limit", "25")); LUCENE_LEADING_WILDCARD = Boolean.parseBoolean(props.getProperty("lucenesearch.leading.wildcard", "false")); diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/Moderator.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/Moderator.java index 8372a812ae..6d9c9bd321 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/Moderator.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/Moderator.java @@ -17,7 +17,6 @@ import org.eclipse.sw360.datahandler.thrift.ThriftClients; import org.eclipse.sw360.datahandler.thrift.attachments.Attachment; import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentContent; -import org.eclipse.sw360.datahandler.thrift.components.Release; import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService; import org.apache.logging.log4j.LogManager; @@ -84,10 +83,6 @@ protected T updateBasicField(U field, FieldMetaData fieldMetaData, T document, T case TType.STRING: case TType.ENUM: - if (document instanceof Release && ((field == Release._Fields.NAME || field == Release._Fields.VERSION) - && "Dummy_Value".equals(documentAdditions.getFieldValue(field)))) { - break; - } document.setFieldValue(field, documentAdditions.getFieldValue(field)); break; case TType.I32: diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java index 79f9e0539b..4916649f68 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java @@ -72,6 +72,9 @@ public class SW360Constants { public static final String TYPE_VULNERABILITYDTO = "vulDTO"; public static final String TYPE_OBLIGATIONELEMENT = "obligationElement"; public static final String TYPE_OBLIGATIONNODE = "obligationNode"; + public static final String TYPE_SPDX_DOCUMENT = "SPDXDocument"; + public static final String TYPE_SPDX_DOCUMENT_CREATION_INFO = "documentCreationInformation"; + public static final String TYPE_SPDX_PACKAGE_INFO = "packageInformation"; /** * Hashmap containing the name field for each type. diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Utils.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Utils.java index 24214da4fa..a5117ea771 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Utils.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Utils.java @@ -39,6 +39,9 @@ import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.ReleaseVulnerabilityRelation; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -305,6 +308,27 @@ public static String printName(User user) { return user.getEmail(); } + public static String printName(SPDXDocument spdx) { + if (spdx == null || isNullOrEmpty(spdx.getId())) { + return "New SPDX Document"; + } + return spdx.getId(); + } + + public static String printName(DocumentCreationInformation documentCreationInfo) { + if (documentCreationInfo == null || isNullOrEmpty(documentCreationInfo.getName())) { + return "New SPDX Document Creation Info"; + } + return documentCreationInfo.getName(); + } + + public static String printName(PackageInformation packageInfo) { + if (packageInfo == null || isNullOrEmpty(packageInfo.getName())) { + return "New SPDX Package Info"; + } + return packageInfo.getName(); + } + public static String printFullname(User user) { if (user == null || isNullOrEmpty(user.getEmail())) { return "New User"; diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/ThriftEnumUtils.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/ThriftEnumUtils.java index 3ede2b1497..ba5f88438d 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/ThriftEnumUtils.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/common/ThriftEnumUtils.java @@ -112,6 +112,7 @@ private ThriftEnumUtils() { .put(AttachmentType.README_OSS, "ReadMe OSS") .put(AttachmentType.OTHER, "Other") .put(AttachmentType.SECURITY_ASSESSMENT, "Security Assessment") + .put(AttachmentType.SBOM, "SBOM") .put(AttachmentType.INITIAL_SCAN_REPORT, "Initial Scan Report") .build(); @@ -137,6 +138,7 @@ private ThriftEnumUtils() { .put(AttachmentType.README_OSS, "RDM") .put(AttachmentType.OTHER, "OTH") .put(AttachmentType.SECURITY_ASSESSMENT, "SECA") + .put(AttachmentType.SBOM, "SBOM") .put(AttachmentType.INITIAL_SCAN_REPORT, "ISR") .build(); @@ -277,13 +279,16 @@ private ThriftEnumUtils() { ECCStatus.REJECTED, "Rejected" ); - private static final ImmutableMap MAP_DOCUMENT_TYPE_STRING = ImmutableMap.of( - DocumentType.COMPONENT, "component" , - DocumentType.RELEASE, "release" , - DocumentType.PROJECT, "project", - DocumentType.LICENSE, "license", - DocumentType.USER, "user" - ); + private static final ImmutableMap MAP_DOCUMENT_TYPE_STRING = ImmutableMap.builder() + .put(DocumentType.COMPONENT, "component" ) + .put(DocumentType.RELEASE, "release") + .put(DocumentType.PROJECT, "project") + .put(DocumentType.LICENSE, "license") + .put(DocumentType.USER, "user") + .put(DocumentType.SPDXDOCUMENT, "spdxDocument") + .put(DocumentType.SPDX_PACKAGE_INFO, "spdxPackageInfo") + .put(DocumentType.SPDX_DOCUMENT_CREATION_INFO, "spdxDocumentCreation") + .build(); private static final ImmutableMap MAP_OBLIGATION_STATUS_STRING = ImmutableMap.builder() .put(ObligationStatus.OPEN, "Open") diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForChangeLog.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForChangeLog.java index 8fafe839bb..d6badd7097 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForChangeLog.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForChangeLog.java @@ -21,6 +21,16 @@ import org.eclipse.sw360.datahandler.thrift.projects.ProjectProjectRelationship; import org.eclipse.sw360.datahandler.thrift.projects.ObligationStatusInfo; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.CheckSum; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.Creator; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.ExternalDocumentReferences; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetRange; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; import org.eclipse.sw360.datahandler.thrift.licenses.Obligation; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -239,11 +249,132 @@ public static abstract class ProjectProjectRelationshipMixin extends ProjectProj @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties({ - "node", - "distribution", - "development", - "obligationType" + "setAlgorithm", + "setChecksumValue", + "setIndex" + }) + public static abstract class CheckSumMixin extends CheckSum { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setAnnotator", + "setAnnotationDate", + "setAnnotationType", + "setSpdxIdRef", + "setAnnotationComment", + "setIndex" + }) + public static abstract class AnnotationsMixin extends Annotations { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setExternalDocumentId", + "setChecksum", + "setSpdxDocument", + "setIndex" + }) + public static abstract class ExternalDocumentReferencesMixin extends ExternalDocumentReferences { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setType", + "setValue", + "setIndex" + }) + public static abstract class CreatorMixin extends Creator { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setLicenseId", + "setExtractedText", + "setLicenseName", + "setLicenseCrossRefs", + "licenseCrossRefsSize", + "licenseCrossRefsIterator", + "setLicenseComment", + "setIndex" + }) + public static abstract class OtherLicensingInformationDetectedMixin extends OtherLicensingInformationDetected { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setExcludedFiles", + "excludedFilesSize", + "excludedFilesIterator", + "setIndex", + "setValue" + }) + public static abstract class PackageVerificationCodeMixin extends PackageVerificationCode { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setReferenceCategory", + "setReferenceLocator", + "setReferenceType", + "setComment", + "setIndex" + }) + public static abstract class ExternalReferenceMixin extends ExternalReference { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setSpdxElementId", + "setRelationshipType", + "setRelatedSpdxElement", + "setRelationshipComment", + "setIndex" + }) + public static abstract class RelationshipsBetweenSPDXElementsMixin extends RelationshipsBetweenSPDXElements { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setSPDXID", + "setSnippetFromFile", + "setSnippetRanges", + "snippetRangesSize", + "snippetRangesIterator", + "setLicenseConcluded", + "setLicenseInfoInSnippets", + "licenseInfoInSnippetsSize", + "licenseInfoInSnippetsIterator", + "setLicenseComments", + "setCopyrightText", + "setComment", + "setName", + "setSnippetAttributionText", + "setIndex", + "spdxid" + }) + public static abstract class SnippetInformationMixin extends SnippetInformation { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setRangeType", + "setStartPointer", + "setEndPointer", + "setReference", + "setIndex" + }) + public static abstract class SnippetRangeMixin extends SnippetRange { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "node", + "distribution", + "development", + "obligationType" }) public static abstract class ObligationMixin extends Obligation { } + } diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForSPDXDocument.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForSPDXDocument.java new file mode 100644 index 0000000000..d997c4494f --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForSPDXDocument.java @@ -0,0 +1,223 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.couchdb; + +import org.eclipse.sw360.datahandler.thrift.ProjectReleaseRelationship; +import org.eclipse.sw360.datahandler.thrift.attachments.Attachment; +import org.eclipse.sw360.datahandler.thrift.changelogs.ChangeLogs; +import org.eclipse.sw360.datahandler.thrift.changelogs.ChangedFields; +import org.eclipse.sw360.datahandler.thrift.changelogs.ReferenceDocData; +import org.eclipse.sw360.datahandler.thrift.components.COTSDetails; +import org.eclipse.sw360.datahandler.thrift.components.ClearingInformation; +import org.eclipse.sw360.datahandler.thrift.components.EccInformation; +import org.eclipse.sw360.datahandler.thrift.components.Repository; +import org.eclipse.sw360.datahandler.thrift.projects.ObligationStatusInfo; +import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; +import org.eclipse.sw360.datahandler.thrift.spdx.annotations.Annotations; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.CheckSum; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.Creator; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.ExternalDocumentReferences; +import org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected.OtherLicensingInformationDetected; +import org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation.SnippetRange; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.ExternalReference; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageVerificationCode; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + +public class DatabaseMixInForSPDXDocument { + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setAnnotator", + "setAnnotationDate", + "setAnnotationType", + "setSpdxIdRef", + "setAnnotationComment", + "setIndex", + "index" + }) + public static abstract class AnnotationsMixin extends Annotations { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setIndex", + "index", + "setAlgorithm", + "setChecksumValue" + }) + public static abstract class CheckSumMixin extends CheckSum { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setReferenceType", + "setIndex", + "setReferenceCategory", + "index", + "setComment", + "setReferenceLocator" + }) + public static abstract class ExternalReferenceMixin extends ExternalReference { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setExternalDocumentId", + "setChecksum", + "setSpdxDocument", + "setIndex", + "index" + }) + public static abstract class ExternalDocumentReferencesMixin extends ExternalDocumentReferences { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setSPDXID", + "setSnippetFromFile", + "setSnippetRanges", + "snippetRangesSize", + "snippetRangesIterator", + "setLicenseConcluded", + "setLicenseInfoInSnippets", + "licenseInfoInSnippetsSize", + "licenseInfoInSnippetsIterator", + "setLicenseComments", + "setCopyrightText", + "setComment", + "setName", + "setSnippetAttributionText", + "setIndex", + "spdxid", + "index" + }) + public static abstract class SnippetInformationMixin extends SnippetInformation { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setRangeType", + "setStartPointer", + "setEndPointer", + "setReference", + "setIndex", + "index" + }) + public static abstract class SnippetRangeMixin extends SnippetRange { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setSpdxElementId", + "setRelationshipType", + "setRelatedSpdxElement", + "setRelationshipComment", + "setIndex", + "index" + }) + public static abstract class RelationshipsBetweenSPDXElementsMixin extends RelationshipsBetweenSPDXElements { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setLicenseId", + "setExtractedText", + "setLicenseName", + "setLicenseCrossRefs", + "licenseCrossRefsSize", + "licenseCrossRefsIterator", + "setLicenseComment", + "setIndex", + "index" + }) + public static abstract class OtherLicensingInformationDetectedMixin extends OtherLicensingInformationDetected { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setExcludedFiles", + "excludedFilesSize", + "excludedFilesIterator", + "setIndex", + "setValue" + }) + public static abstract class PackageVerificationCodeMixin extends PackageVerificationCode { + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "setAnnotations", + "type", + "setPermissions", + "permissions", + "setAttributionText", + "setId", + "id", + "attributionTextSize", + "setLicenseDeclared", + "setSupplier", + "setLicenseComments", + "checksumsIterator", + "setFilesAnalyzed", + "setPackageFileName", + "setPackageComment", + "setVersionInfo", + "revision", + "setExternalRefs", + "setName", + "permissionsSize", + "setDescription", + "setSourceInfo", + "setHomepage", + "setRevision", + "setLicenseInfoFromFiles", + "checksumsSize", + "setChecksums", + "annotationsSize", + "setSummary", + "setOriginator", + "externalRefsSize", + "setPackageVerificationCode", + "setLicenseConcluded", + "spdxDocumentId", + "setType", + "documentState", + "setSpdxDocumentId", + "setDownloadLocation", + "licenseInfoFromFilesSize", + "setCopyrightText", + "setValue", + "excludedFilesSize", + "setExcludedFiles", + "createdBy", + "setCreatedBy", + "setDocumentState", + "setSPDXID", + "annotationsIterator", + "externalRefsIterator", + "attributionTextIterator", + "index", + "setIndex", + "relationshipsSize", + "spdxid", + "setRelationships", + "relationshipsIterator", + "licenseInfoFromFilesIterator" + }) + public static abstract class PackageInformationMixin extends PackageInformation { + } +} diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/ComponentPermissions.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/ComponentPermissions.java index bce510de7b..927ddf8d96 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/ComponentPermissions.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/ComponentPermissions.java @@ -147,9 +147,6 @@ protected Set getUserEquivalentOwnerGroup(){ departments.addAll(user.getSecondaryDepartmentsAndRoles().keySet()); } departments.add(user.getDepartment()); - if(!PermissionUtils.IS_COMPONENT_VISIBILITY_RESTRICTION_ENABLED) { - return departments; - } Set finalDepartments = new HashSet(); String departmentIfUserInBU = getDepartmentIfUserInBU(document, departments); finalDepartments.add(departmentIfUserInBU); diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/PermissionUtils.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/PermissionUtils.java index 07a09319a0..d07797f4b4 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/PermissionUtils.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/PermissionUtils.java @@ -22,6 +22,9 @@ import org.eclipse.sw360.datahandler.thrift.users.UserGroup; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; /** * Created by bodet on 16/02/15. @@ -156,6 +159,12 @@ public static DocumentPermissions makePermission(T document, User user) { return (DocumentPermissions) new UserPermissions((User) document, user); } else if (document instanceof Vulnerability) { return (DocumentPermissions) new VulnerabilityPermissions((Vulnerability) document, user); + } else if (document instanceof SPDXDocument) { + return (DocumentPermissions) new SpdxDocumentPermissions((SPDXDocument) document, user); + } else if (document instanceof DocumentCreationInformation) { + return (DocumentPermissions) new SpdxDocumentCreationInfoPermissions((DocumentCreationInformation) document, user); + } else if (document instanceof PackageInformation) { + return (DocumentPermissions) new SpdxPackageInfoPermissions((PackageInformation) document, user); } else { throw new IllegalArgumentException("Invalid input type!"); } diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentCreationInfoPermissions.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentCreationInfoPermissions.java new file mode 100644 index 0000000000..145b169c19 --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentCreationInfoPermissions.java @@ -0,0 +1,51 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.permissions; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import java.util.Map; +import java.util.Set; +import static org.eclipse.sw360.datahandler.common.CommonUtils.toSingletonSet; + +public class SpdxDocumentCreationInfoPermissions extends DocumentPermissions { + + private final Set moderators; + private final Set createdBy; + + protected SpdxDocumentCreationInfoPermissions(DocumentCreationInformation document, User user) { + super(document, user); + this.createdBy = toSingletonSet(document.createdBy); + moderators = toSingletonSet(document.createdBy); + } + + @Override + public void fillPermissions(DocumentCreationInformation spdx, Map permissions) { + spdx.permissions = permissions; + } + + @Override + public boolean isActionAllowed(RequestedAction action) { + return getStandardPermissions(action); + } + + @Override + protected Set getContributors() { + return moderators; + } + + @Override + protected Set getModerators() { + return moderators; + } +} diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentPermissions.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentPermissions.java new file mode 100644 index 0000000000..3674d7aaef --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentPermissions.java @@ -0,0 +1,51 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.permissions; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import java.util.Map; +import java.util.Set; +import static org.eclipse.sw360.datahandler.common.CommonUtils.toSingletonSet; + +public class SpdxDocumentPermissions extends DocumentPermissions { + + private final Set moderators; + private final Set createdBy; + + protected SpdxDocumentPermissions(SPDXDocument document, User user) { + super(document, user); + this.createdBy = toSingletonSet(document.createdBy); + moderators = toSingletonSet(document.createdBy); + } + + @Override + public void fillPermissions(SPDXDocument spdx, Map permissions) { + spdx.permissions = permissions; + } + + @Override + public boolean isActionAllowed(RequestedAction action) { + return getStandardPermissions(action); + } + + @Override + protected Set getContributors() { + return moderators; + } + + @Override + protected Set getModerators() { + return moderators; + } +} diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxPackageInfoPermissions.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxPackageInfoPermissions.java new file mode 100644 index 0000000000..d211dbca7f --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxPackageInfoPermissions.java @@ -0,0 +1,51 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.sw360.datahandler.permissions; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; +import org.eclipse.sw360.datahandler.thrift.users.RequestedAction; +import org.eclipse.sw360.datahandler.thrift.users.User; + +import java.util.Map; +import java.util.Set; +import static org.eclipse.sw360.datahandler.common.CommonUtils.toSingletonSet; + +public class SpdxPackageInfoPermissions extends DocumentPermissions { + + private final Set moderators; + private final Set createdBy; + + protected SpdxPackageInfoPermissions(PackageInformation packageInfo, User user) { + super(packageInfo, user); + this.createdBy = toSingletonSet(packageInfo.createdBy); + moderators = toSingletonSet(packageInfo.createdBy); + } + + @Override + public void fillPermissions(PackageInformation packageInfo, Map permissions) { + packageInfo.permissions = permissions; + } + + @Override + public boolean isActionAllowed(RequestedAction action) { + return getStandardPermissions(action); + } + + @Override + protected Set getContributors() { + return moderators; + } + + @Override + protected Set getModerators() { + return moderators; + } +} diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftClients.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftClients.java index 06f60ac338..9d38259274 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftClients.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftClients.java @@ -18,7 +18,6 @@ import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.thrift.TConfiguration; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.THttpClient; @@ -41,6 +40,10 @@ import org.eclipse.sw360.datahandler.thrift.users.UserService; import org.eclipse.sw360.datahandler.thrift.vendors.VendorService; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocumentService; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformationService; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformationService; +import org.eclipse.sw360.datahandler.thrift.spdx.fileinformation.FileInformationService; import java.net.MalformedURLException; import java.net.URL; @@ -62,8 +65,6 @@ public class ThriftClients { public static final String BACKEND_PROXY_URL; public static final int THRIFT_CONNECTION_TIMEOUT; public static final int THRIFT_READ_TIMEOUT; - public static final int THRIFT_MAX_MESSAGE_SIZE; - public static final int THRIFT_MAX_FRAME_SIZE; //! Service addresses private static final String ATTACHMENT_SERVICE_URL = "/attachments/thrift"; @@ -83,6 +84,11 @@ public class ThriftClients { private static final String WSIMPORT_SERVICE_URL = "/wsimport/thrift"; private static final String CHANGELOGS_SERVICE_URL = "/changelogs/thrift"; private static final String HEALTH_SERVICE_URL = "/health/thrift"; + private static final String SPDX_SERVICE_URL = "/spdxdocument/thrift"; + private static final String SPDX_DOCUMENT_INFO_SERVICE_URL = "/spdxdocumentcreationinfo/thrift"; + private static final String SPDX_PACKAGE_INFO_SERVICE_URL = "/spdxpackageinfo/thrift"; + private static final String SPDX_FILE_INFO_SERVICE_URL = "/fileinformation/thrift"; + // A service which has to be scheduled by the scheduler should be registered here! // names of services that can be scheduled by the schedule service, i.e. that have an "update" method @@ -99,9 +105,6 @@ public class ThriftClients { THRIFT_CONNECTION_TIMEOUT = Integer.valueOf(props.getProperty("backend.timeout.connection", "5000")); THRIFT_READ_TIMEOUT = Integer.valueOf(props.getProperty("backend.timeout.read", "600000")); - THRIFT_MAX_MESSAGE_SIZE = Integer.valueOf(props.getProperty("backend.thrift.max.message.size", String.valueOf(TConfiguration.DEFAULT_MAX_MESSAGE_SIZE))); - THRIFT_MAX_FRAME_SIZE = Integer.valueOf(props.getProperty("backend.thrift.max.frame.size", String.valueOf(TConfiguration.DEFAULT_MAX_FRAME_SIZE))); - log.info("The following configuration will be used for connections to the backend:\n" + "\tURL : " + BACKEND_URL + "\n" + "\tProxy : " + BACKEND_PROXY_URL + "\n" + @@ -117,18 +120,15 @@ public ThriftClients() { private static TProtocol makeProtocol(String url, String service) { THttpClient thriftClient = null; final String destinationAddress = url + service; - final TConfiguration thriftConfigure = TConfiguration.custom().setMaxMessageSize(THRIFT_MAX_MESSAGE_SIZE) - .setMaxFrameSize(THRIFT_MAX_FRAME_SIZE).build(); - try { if (BACKEND_PROXY_URL != null) { URL proxyUrl = new URL(BACKEND_PROXY_URL); HttpHost proxy = new HttpHost(proxyUrl.getHost(), proxyUrl.getPort(), proxyUrl.getProtocol()); DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy); CloseableHttpClient httpClient = HttpClients.custom().setRoutePlanner(routePlanner).build(); - thriftClient = new THttpClient(thriftConfigure, destinationAddress, httpClient); + thriftClient = new THttpClient(destinationAddress, httpClient); } else { - thriftClient = new THttpClient(thriftConfigure, destinationAddress); + thriftClient = new THttpClient(destinationAddress); } thriftClient.setConnectTimeout(THRIFT_CONNECTION_TIMEOUT); thriftClient.setReadTimeout(THRIFT_READ_TIMEOUT); @@ -207,4 +207,21 @@ public ChangeLogsService.Iface makeChangeLogsClient() { public HealthService.Iface makeHealthClient() { return new HealthService.Client(makeProtocol(BACKEND_URL, HEALTH_SERVICE_URL)); } + + public SPDXDocumentService.Iface makeSPDXClient() { + return new SPDXDocumentService.Client(makeProtocol(BACKEND_URL, SPDX_SERVICE_URL)); + } + + public DocumentCreationInformationService.Iface makeSPDXDocumentInfoClient() { + return new DocumentCreationInformationService.Client(makeProtocol(BACKEND_URL, SPDX_DOCUMENT_INFO_SERVICE_URL)); + } + + public PackageInformationService.Iface makeSPDXPackageInfoClient() { + return new PackageInformationService.Client(makeProtocol(BACKEND_URL, SPDX_PACKAGE_INFO_SERVICE_URL)); + } + + public FileInformationService.Iface makeSPDXFileInfoClient() { + return new FileInformationService.Client(makeProtocol(BACKEND_URL, SPDX_FILE_INFO_SERVICE_URL)); + } + } diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftUtils.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftUtils.java index 91acb2d450..95f1186758 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftUtils.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftUtils.java @@ -30,6 +30,10 @@ import org.eclipse.sw360.datahandler.thrift.users.User; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; +import org.eclipse.sw360.datahandler.thrift.spdx.fileinformation.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -67,6 +71,10 @@ public class ThriftUtils { .add(ExternalToolProcess.class, ExternalToolProcessStep.class) // external tools like Fossology service .add(Vulnerability.class, ReleaseVulnerabilityRelation.class, ProjectVulnerabilityRating.class) .add(ChangeLogs.class) // Changelog Service + .add(SPDXDocument.class ) // SPDX Document service + .add(DocumentCreationInformation.class ) // Document Creation Information service + .add(PackageInformation.class ) // Package Information service + .add(FileInformation.class) // File Information Service .build(); public static final List> THRIFT_NESTED_CLASSES = ImmutableList.>builder() diff --git a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftValidate.java b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftValidate.java index 570a8868a4..7667e769cd 100644 --- a/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftValidate.java +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/thrift/ThriftValidate.java @@ -17,9 +17,12 @@ import org.eclipse.sw360.datahandler.thrift.licenses.*; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.projects.ProjectClearingState; +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; import org.eclipse.sw360.datahandler.thrift.projects.ObligationList; import org.eclipse.sw360.datahandler.thrift.users.User; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation; import java.util.Collection; import java.util.Collections; @@ -255,4 +258,31 @@ public static void prepareProjectObligation(ObligationList obligation) throws SW assertNotEmpty(obligation.getLinkedObligationStatus().keySet(), "linked obligtions cannot be empty"); obligation.setType(TYPE_PROJECT_OBLIGATION); } + + public static void prepareSPDXDocument(SPDXDocument spdx) throws SW360Exception { + // Check required fields + + // Check type + spdx.setType(TYPE_SPDX_DOCUMENT); + // Unset temporary fields + spdx.unsetPermissions(); + } + + public static void prepareSpdxDocumentCreationInfo(DocumentCreationInformation documentCreationInfo) throws SW360Exception { + // Check required fields + + // Check type + documentCreationInfo.setType(TYPE_SPDX_DOCUMENT_CREATION_INFO); + // Unset temporary fields + documentCreationInfo.unsetPermissions(); +} + + public static void prepareSpdxPackageInfo(PackageInformation packageInfo) throws SW360Exception { + // Check required fields + + // Check type + packageInfo.setType(TYPE_SPDX_PACKAGE_INFO); + // Unset temporary fields + packageInfo.unsetPermissions(); + } } diff --git a/libraries/lib-datahandler/src/main/resources/sw360.properties b/libraries/lib-datahandler/src/main/resources/sw360.properties index fc4cda098a..a9c31f396c 100644 --- a/libraries/lib-datahandler/src/main/resources/sw360.properties +++ b/libraries/lib-datahandler/src/main/resources/sw360.properties @@ -43,9 +43,5 @@ ## first byte of the response is available. #backend.timeout.read = 600000 -## These two properties used to set max message size and frame size of thrift transport -#backend.thrift.max.message.size=104857600 -#backend.thrift.max.frame.size=16384000 - ## This property is used to enable the component visibility restriction feature. #component.visibility.restriction.enabled=true \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/attachments.thrift b/libraries/lib-datahandler/src/main/thrift/attachments.thrift index e42d9b7a97..5e4cdfad9a 100644 --- a/libraries/lib-datahandler/src/main/thrift/attachments.thrift +++ b/libraries/lib-datahandler/src/main/thrift/attachments.thrift @@ -39,8 +39,9 @@ enum AttachmentType { SCREENSHOT = 15, OTHER = 16, README_OSS = 17, - SECURITY_ASSESSMENT = 18, - INITIAL_SCAN_REPORT = 19 + SBOM = 18, + SECURITY_ASSESSMENT = 19, + INITIAL_SCAN_REPORT = 20 } enum CheckStatus { diff --git a/libraries/lib-datahandler/src/main/thrift/changelogs.thrift b/libraries/lib-datahandler/src/main/thrift/changelogs.thrift index 94b0b0fed5..aa9027e123 100644 --- a/libraries/lib-datahandler/src/main/thrift/changelogs.thrift +++ b/libraries/lib-datahandler/src/main/thrift/changelogs.thrift @@ -31,7 +31,13 @@ enum Operation { MERGE_RELEASE = 10, OBLIGATION_UPDATE = 11, OBLIGATION_ADD = 12, - SPLIT_COMPONENT = 13 + SPLIT_COMPONENT = 13, + SPDXDOCUMENT_CREATE = 14, + SPDXDOCUMENT_DELETE = 15, + SPDX_DOCUMENT_CREATION_INFO_CREATE = 16, + SPDX_DOCUMENT_CREATION_INFO_DELETE = 17, + SPDX_PACKAGE_INFO_CREATE = 18, + SPDX_PACKAGE_INFO_DELETE = 19 } struct ChangeLogs { diff --git a/libraries/lib-datahandler/src/main/thrift/components.thrift b/libraries/lib-datahandler/src/main/thrift/components.thrift index a5cbbbfcc9..13ff851d63 100644 --- a/libraries/lib-datahandler/src/main/thrift/components.thrift +++ b/libraries/lib-datahandler/src/main/thrift/components.thrift @@ -27,6 +27,7 @@ typedef sw360.MainlineState MainlineState typedef sw360.ProjectReleaseRelationship ProjectReleaseRelationship typedef sw360.SW360Exception SW360Exception typedef sw360.PaginationData PaginationData +typedef sw360.ImportBomRequestPreparation ImportBomRequestPreparation typedef attachments.Attachment Attachment typedef attachments.FilledAttachment FilledAttachment typedef users.User User @@ -272,6 +273,8 @@ struct Release { 90: optional DocumentState documentState, 200: optional map permissions, + + 400: optional string spdxId, 204: optional string modifiedBy, // Last Modified By User Email 205: optional string modifiedOn, // Last Modified Date YYYY-MM-dd } @@ -828,10 +831,15 @@ service ComponentService { */ string getCyclicLinkedReleasePath(1: Release release, 2: User user); + // /** + // * parse a bom file and write the information to SW360 + // **/ + ImportBomRequestPreparation prepareImportBom(1: User user, 2:string attachmentContentId); + /** * parse a bom file and write the information to SW360 **/ - RequestSummary importBomFromAttachmentContent(1: User user, 2:string attachmentContentId); + RequestSummary importBomFromAttachmentContent(1: User user, 2:string attachmentContentId, 3:string newReleaseVersion, 4:string releaseId, 5:string rdfFilePath); /** * split data like releases and attachments from source component to target component. @@ -843,6 +851,10 @@ service ComponentService { */ list getAllReleasesForUser(1: User user); + /** + * parse a bom file and write the information to SW360 + **/ + RequestSummary exportSPDX(1: User user, 2:string releaseId, 3:string outputFormat); /** * Send email to the user once spreadsheet export completed */ diff --git a/libraries/lib-datahandler/src/main/thrift/moderation.thrift b/libraries/lib-datahandler/src/main/thrift/moderation.thrift index 1931911ca6..1ff2843294 100644 --- a/libraries/lib-datahandler/src/main/thrift/moderation.thrift +++ b/libraries/lib-datahandler/src/main/thrift/moderation.thrift @@ -14,6 +14,9 @@ include "components.thrift" include "projects.thrift" include "users.thrift" include "licenses.thrift" +include "spdx/spdxdocument.thrift" +include "spdx/documentcreationinformation.thrift" +include "spdx/packageinformation.thrift" namespace java org.eclipse.sw360.datahandler.thrift.moderation namespace php sw360.thrift.moderation @@ -31,6 +34,9 @@ typedef licenses.License License typedef licenses.Obligation Obligation typedef components.ComponentType ComponentType typedef projects.ClearingRequest ClearingRequest +typedef spdxdocument.SPDXDocument SPDXDocument +typedef documentcreationinformation.DocumentCreationInformation DocumentCreationInformation +typedef packageinformation.PackageInformation PackageInformation enum DocumentType { COMPONENT = 1, @@ -38,6 +44,9 @@ enum DocumentType { PROJECT = 3, LICENSE = 4, USER = 5, + SPDXDOCUMENT = 6, + SPDX_DOCUMENT_CREATION_INFO = 7, + SPDX_PACKAGE_INFO = 8, } struct ModerationRequest { @@ -74,6 +83,13 @@ struct ModerationRequest { 32: optional Project projectDeletions, 33: optional License licenseDeletions, + 50: optional SPDXDocument SPDXDocumentAdditions, + 51: optional SPDXDocument SPDXDocumentDeletions, + 52: optional DocumentCreationInformation documentCreationInfoAdditions, + 53: optional DocumentCreationInformation documentCreationInfoDeletions, + 54: optional PackageInformation packageInfoAdditions, + 55: optional PackageInformation packageInfoDeletions, + } service ModerationService { @@ -115,6 +131,27 @@ service ModerationService { **/ RequestStatus createLicenseRequest(1: License license, 2: User user); + /** + * write moderation request for SPDXDocument to database, + * differences are written as additions and deletions to moderation request, + * set requestingUser of moderation request to user + **/ + RequestStatus createSPDXDocumentRequest(1: SPDXDocument spdx, 2: User user); + + /** + * write moderation request for spdx document creation info to database, + * differences are written as additions and deletions to moderation request, + * set requestingUser of moderation request to user + **/ + RequestStatus createSpdxDocumentCreationInfoRequest(1: DocumentCreationInformation documentCreationInfo, 2: User user); + + /** + * write moderation request for spdx document creation info to database, + * differences are written as additions and deletions to moderation request, + * set requestingUser of moderation request to user + **/ + RequestStatus createSpdxPackageInfoRequest(1: PackageInformation packageInfo, 2: User user); + /** * write moderation request for activating a user account to database **/ @@ -138,6 +175,24 @@ service ModerationService { **/ oneway void createProjectDeleteRequest(1: Project project, 2: User user); + /** + * write moderation request for deleting project to database, + * set requestingUser of moderation request to user + **/ + oneway void createSPDXDocumentDeleteRequest(1: SPDXDocument spdx, 2: User user); + + /** + * write moderation request for deleting spdx document creation info to database, + * set requestingUser of moderation request to user + **/ + oneway void createSpdxDocumentCreationInfoDeleteRequest(1: DocumentCreationInformation documentCreationInfo, 2: User user); + + /** + * write moderation request for deleting spdx package info to database, + * set requestingUser of moderation request to user + **/ + oneway void createSpdxPackageInfoDeleteRequest(1: PackageInformation packageInfo, 2: User user); + /** * get list of moderation requests for document with documentId currently present in database **/ diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/annotations.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/annotations.thrift new file mode 100644 index 0000000000..d52061db6e --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/annotations.thrift @@ -0,0 +1,21 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +namespace java org.eclipse.sw360.datahandler.thrift.spdx.annotations +namespace php sw360.thrift.spdx.annotations + +struct Annotations { + 1: optional string annotator, // 12.1 + 2: optional string annotationDate, // 12.2 + 3: optional string annotationType, // 12.3 + 4: optional string spdxIdRef, // 12.4 + 5: optional string annotationComment, // 12.5 + 6: optional i32 index, +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/documentcreationinformation.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/documentcreationinformation.thrift new file mode 100644 index 0000000000..af5d2d4858 --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/documentcreationinformation.thrift @@ -0,0 +1,75 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +include "sw360.thrift" +include "users.thrift" + +namespace java org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation +namespace php sw360.thrift.spdx.documentcreationinformation + +typedef sw360.RequestStatus RequestStatus +typedef sw360.RequestSummary RequestSummary +typedef sw360.AddDocumentRequestSummary AddDocumentRequestSummary +typedef sw360.DocumentState DocumentState +typedef sw360.SW360Exception SW360Exception +typedef sw360.PaginationData PaginationData +typedef users.User User +typedef users.RequestedAction RequestedAction + +struct DocumentCreationInformation { + 1: optional string id, + 2: optional string revision, + 3: optional string type = "documentCreationInformation", + 4: optional string spdxDocumentId, // Id of the parent SPDX Document + 5: optional string spdxVersion, // 6.1 + 6: optional string dataLicense, // 6.2 + 7: optional string SPDXID, // 6.3 + 8: optional string name, // 6.4 + 9: optional string documentNamespace, // 6.5 + 10: optional set externalDocumentRefs, // 6.6 + 11: optional string licenseListVersion, // 6.7 + 12: optional set creator, // 6.8 + 13: optional string created, // 6.9 + 14: optional string creatorComment, // 6.10 + 15: optional string documentComment, // 6.11 + // Information for ModerationRequests + 20: optional DocumentState documentState, + 21: optional map permissions, + 22: optional string createdBy, +} + +struct ExternalDocumentReferences { + 1: optional string externalDocumentId, + 2: optional CheckSum checksum, + 3: optional string spdxDocument, + 4: optional i32 index, +} + +struct CheckSum { + 1: optional string algorithm, + 2: optional string checksumValue, + 3: optional i32 index, +} + +struct Creator { + 1: optional string type, + 2: optional string value, + 3: optional i32 index, +} + +service DocumentCreationInformationService { + list getDocumentCreationInformationSummary(1: User user); + DocumentCreationInformation getDocumentCreationInformationById(1: string id, 2: User user); + DocumentCreationInformation getDocumentCreationInfoForEdit(1: string id, 2: User user); + AddDocumentRequestSummary addDocumentCreationInformation(1: DocumentCreationInformation documentCreationInformation, 2: User user); + RequestStatus updateDocumentCreationInformation(1: DocumentCreationInformation documentCreationInformation, 2: User user); + RequestStatus updateDocumentCreationInfomationFromModerationRequest(1: DocumentCreationInformation documentCreationInfoAdditions, 2: DocumentCreationInformation documentCreationInfoDeletions, 3: User user); + RequestStatus deleteDocumentCreationInformation(1: string id, 2: User user); +} diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/fileinformation.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/fileinformation.thrift new file mode 100644 index 0000000000..be2f77ab32 --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/fileinformation.thrift @@ -0,0 +1,65 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +include "sw360.thrift" +include "users.thrift" +include "documentcreationinformation.thrift" +include "snippetinformation.thrift" +include "annotations.thrift" +include "otherlicensinginformationdetected.thrift" + + +namespace java org.eclipse.sw360.datahandler.thrift.spdx.fileinformation +namespace php sw360.thrift.spdx.fileinformation + +typedef sw360.RequestStatus RequestStatus +typedef sw360.RequestSummary RequestSummary +typedef sw360.AddDocumentRequestSummary AddDocumentRequestSummary +typedef sw360.DocumentState DocumentState +typedef sw360.SW360Exception SW360Exception +typedef sw360.PaginationData PaginationData +typedef users.User User +typedef users.RequestedAction RequestedAction +typedef documentcreationinformation.CheckSum CheckSum +typedef snippetinformation.SnippetInformation SnippetInformation +typedef annotations.Annotations Annotation +typedef otherlicensinginformationdetected.OtherLicensingInformationDetected OtherLicensingInformationDetected + +struct FileInformation { + 1: optional string id, + 2: optional string revision, + 3: optional string type = "spdxFileInformation", + 4: optional string fileName, + 5: optional string SPDXID, + 6: optional set fileTypes, + 7: optional set checksums, + 8: optional string licenseConcluded, + 9: optional set licenseInfoInFiles, + 10: optional string licenseComments, + 11: optional string copyrightText, + 12: optional string fileComment, + 13: optional string noticeText, + 14: optional set fileContributors, + 15: optional set fileAttributionText, + 16: optional set snippetInformation, + 17: optional set hasExtractedLicensingInfos, + 18: optional set annotations, +} + +service FileInformationService { + list getFileInformationsShort(1: set ids, 2: User user); + list getFileInformationSummary(1: User user); + FileInformation getFileInformationById(1: string id, 2: User user); + RequestStatus addFileInformation(1: FileInformation fileInformation, 2: User user); + AddDocumentRequestSummary addFileInformations(1: set fileInformations, 2: User user); + RequestStatus updateFileInformation(1: FileInformation fileInformation, 2: User user); + RequestSummary updateFileInformations(1: set fileInformations, 2: User user); + RequestStatus deleteFileInformation(1: string id, 2: User user); +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/otherlicensinginformationdetected.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/otherlicensinginformationdetected.thrift new file mode 100644 index 0000000000..9c3ef13cc5 --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/otherlicensinginformationdetected.thrift @@ -0,0 +1,21 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +namespace java org.eclipse.sw360.datahandler.thrift.spdx.otherlicensinginformationdetected +namespace php sw360.thrift.spdx.otherlicensinginformationdetected + +struct OtherLicensingInformationDetected { + 1: optional string licenseId, // 10.1 + 2: optional string extractedText, // 10.2 + 3: optional string licenseName, // 10.3 + 4: optional set licenseCrossRefs, // 10.4 + 5: optional string licenseComment, // 10.5 + 6: optional i32 index, +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/packageinformation.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/packageinformation.thrift new file mode 100644 index 0000000000..2c7f75f468 --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/packageinformation.thrift @@ -0,0 +1,92 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +include "sw360.thrift" +include "users.thrift" +include "documentcreationinformation.thrift" +include "annotations.thrift" +include "relationshipsbetweenspdxelements.thrift" + +namespace java org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo +namespace php sw360.thrift.spdx.spdxpackageinfo + +typedef sw360.RequestStatus RequestStatus +typedef sw360.RequestSummary RequestSummary +typedef sw360.AddDocumentRequestSummary AddDocumentRequestSummary +typedef sw360.DocumentState DocumentState +typedef sw360.SW360Exception SW360Exception +typedef sw360.PaginationData PaginationData +typedef users.User User +typedef users.RequestedAction RequestedAction +typedef documentcreationinformation.CheckSum CheckSum +typedef annotations.Annotations Annotation +typedef relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements RelationshipsBetweenSPDXElements + +struct PackageInformation { + 1: optional string id, + 2: optional string revision, + 3: optional string type = "packageInformation", + 4: optional string spdxDocumentId, // Id of the parent SPDX Document + 5: optional string name, // 7.1 + 6: optional string SPDXID, // 7.2 + 7: optional string versionInfo, // 7.3 + 8: optional string packageFileName, // 7.4 + 9: optional string supplier, // 7.5 + 10: optional string originator, // 7.6 + 11: optional string downloadLocation, // 7.7 + 12: optional bool filesAnalyzed, // 7.8 + 13: optional PackageVerificationCode packageVerificationCode, // 7.9 + 14: optional set checksums, // 7.10 + 15: optional string homepage, // 7.11 + 16: optional string sourceInfo, // 7.12 + 17: optional string licenseConcluded, // 7.13 + 18: optional set licenseInfoFromFiles, // 7.14 + 19: optional string licenseDeclared, // 7.15 + 20: optional string licenseComments, // 7.16 + 21: optional string copyrightText, // 7.17 + 22: optional string summary, // 7.18 + 23: optional string description, // 7.19 + 24: optional string packageComment, // 7.20 + 25: optional set externalRefs, //7.21 + 26: optional set attributionText, // 7.22 + 27: optional set annotations, // 7.23 + // Information for ModerationRequests + 30: optional DocumentState documentState, + 31: optional map permissions, + 32: optional string createdBy, + 33: optional i32 index, + 34: optional set relationships, // 11. Relationships + +} + +struct PackageVerificationCode { + 1: optional set excludedFiles, + 2: optional string value, +} + +struct ExternalReference { + 1: optional string referenceCategory, + 2: optional string referenceLocator, + 3: optional string referenceType, + 4: optional string comment, + 5: optional i32 index, +} + +service PackageInformationService { + list getPackageInformationSummary(1: User user); + PackageInformation getPackageInformationById(1: string id, 2: User user); + PackageInformation getPackageInformationForEdit(1: string id, 2: User user); + AddDocumentRequestSummary addPackageInformation(1: PackageInformation packageInformation, 2: User user); + AddDocumentRequestSummary addPackageInformations(1: set packageInformations, 2: User user); + RequestStatus updatePackageInformation(1: PackageInformation packageInformation, 2: User user); + RequestSummary updatePackageInformations(1: set packageInformations, 2: User user); + RequestStatus updatePackageInfomationFromModerationRequest(1: PackageInformation packageInfoAdditions, 2: PackageInformation packageInfoDeletions, 3: User user); + RequestStatus deletePackageInformation(1: string id, 2: User user); +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/relationshipsbetweenspdxelements.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/relationshipsbetweenspdxelements.thrift new file mode 100644 index 0000000000..d3b2356bbd --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/relationshipsbetweenspdxelements.thrift @@ -0,0 +1,20 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +namespace java org.eclipse.sw360.datahandler.thrift.spdx.relationshipsbetweenspdxelements +namespace php sw360.thrift.spdx.relationshipsbetweenspdxelements + +struct RelationshipsBetweenSPDXElements { + 1: optional string spdxElementId, // 11.1 + 2: optional string relationshipType, // 11.1 + 3: optional string relatedSpdxElement, // 11.1 + 4: optional string relationshipComment, // 11.2 + 5: optional i32 index, +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/snippetinformation.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/snippetinformation.thrift new file mode 100644 index 0000000000..22b336b567 --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/snippetinformation.thrift @@ -0,0 +1,34 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +namespace java org.eclipse.sw360.datahandler.thrift.spdx.snippetinformation +namespace php sw360.thrift.spdx.snippetinformation + +struct SnippetInformation { + 1: optional string SPDXID, // 9.1 + 2: optional string snippetFromFile , // 9.2 + 3: optional set snippetRanges, // 9.3, 9.4 + 4: optional string licenseConcluded, // 9.5 + 5: optional set licenseInfoInSnippets, // 9.6 + 6: optional string licenseComments, // 9.7 + 7: optional string copyrightText, // 9.8 + 8: optional string comment, // 9.9 + 9: optional string name, // 9.10 + 10: optional string snippetAttributionText, // 9.11 + 11: optional i32 index, +} + +struct SnippetRange { + 1: optional string rangeType, + 2: optional string startPointer, + 3: optional string endPointer, + 4: optional string reference, + 5: optional i32 index, +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/spdx/spdxdocument.thrift b/libraries/lib-datahandler/src/main/thrift/spdx/spdxdocument.thrift new file mode 100644 index 0000000000..cb9cda7adc --- /dev/null +++ b/libraries/lib-datahandler/src/main/thrift/spdx/spdxdocument.thrift @@ -0,0 +1,60 @@ +/* + * Copyright TOSHIBA CORPORATION, 2021. Part of the SW360 Portal Project. + * Copyright Toshiba Software Development (Vietnam) Co., Ltd., 2021. Part of the SW360 Portal Project. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +include "sw360.thrift" +include "users.thrift" +include "snippetinformation.thrift" +include "relationshipsbetweenspdxelements.thrift" +include "annotations.thrift" +include "otherlicensinginformationdetected.thrift" + +namespace java org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument +namespace php sw360.thrift.spdx.spdxdocument + +typedef sw360.RequestStatus RequestStatus +typedef sw360.RequestSummary RequestSummary +typedef sw360.AddDocumentRequestSummary AddDocumentRequestSummary +typedef sw360.DocumentState DocumentState +typedef sw360.SW360Exception SW360Exception +typedef sw360.PaginationData PaginationData +typedef users.User User +typedef users.RequestedAction RequestedAction +typedef snippetinformation.SnippetInformation SnippetInformation +typedef relationshipsbetweenspdxelements.RelationshipsBetweenSPDXElements RelationshipsBetweenSPDXElements +typedef annotations.Annotations Annotations +typedef otherlicensinginformationdetected.OtherLicensingInformationDetected OtherLicensingInformationDetected + +struct SPDXDocument { + 1: optional string id, + 2: optional string revision, + 3: optional string type = "SPDXDocument", + 4: optional string releaseId, // Id of the parent release + 5: optional string spdxDocumentCreationInfoId, // Id of Document Creation Info + 6: optional set spdxPackageInfoIds, // Ids of Package Info + 7: optional set spdxFileInfoIds, // Ids of File Info + 8: optional set snippets, // 9. Snippet Information + 9: optional set relationships, // 11. Relationships + 10: optional set annotations, // 12. Annotations + 11: optional set otherLicensingInformationDetecteds, // 10. Other Licensing Information Detected + // Information for ModerationRequests + 20: optional DocumentState documentState, + 21: optional map permissions, + 22: optional string createdBy, +} + +service SPDXDocumentService { + list getSPDXDocumentSummary(1: User user); + SPDXDocument getSPDXDocumentById(1: string id, 2: User user); + SPDXDocument getSPDXDocumentForEdit(1: string id, 2: User user); + AddDocumentRequestSummary addSPDXDocument(1: SPDXDocument spdx, 2: User user); + RequestStatus updateSPDXDocument(1: SPDXDocument spdx, 2: User user); + RequestStatus updateSPDXDocumentFromModerationRequest(1: SPDXDocument spdxAdditions, 2: SPDXDocument spdxDeletions, 3: User user); + RequestStatus deleteSPDXDocument(1: string id, 2: User user); +} \ No newline at end of file diff --git a/libraries/lib-datahandler/src/main/thrift/sw360.thrift b/libraries/lib-datahandler/src/main/thrift/sw360.thrift index ad62816f72..7eaaf9f3a6 100644 --- a/libraries/lib-datahandler/src/main/thrift/sw360.thrift +++ b/libraries/lib-datahandler/src/main/thrift/sw360.thrift @@ -186,6 +186,15 @@ struct AddDocumentRequestSummary { 3: optional string message; } +struct ImportBomRequestPreparation { + 1: required RequestStatus requestStatus; + 2: optional bool isComponentDuplicate; + 3: optional bool isReleaseDuplicate; + 4: optional string name; + 5: optional string version; + 6: optional string message; +} + struct CustomProperties { 1: optional string id, 2: optional string revision, diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/changelog/ChangeLogController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/changelog/ChangeLogController.java index 1651d787d7..fd8ad31469 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/changelog/ChangeLogController.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/changelog/ChangeLogController.java @@ -77,6 +77,7 @@ public ResponseEntity getChangeLogForDocument(Pageable pageable, @PathVariable(" ResourceClassNotFoundException { User sw360User = restControllerHelper.getSw360UserFromAuthentication(); List changelogs = sw360ChangeLogService.getChangeLogsByDocumentId(docId, sw360User); + changelogs.stream().forEach(cl -> cl.setChangeTimestamp(cl.getChangeTimestamp().split(" ")[0])); PaginationResult paginationResult = restControllerHelper.createPaginationResult(request, pageable, changelogs, SW360Constants.TYPE_CHANGELOG); ObjectMapper mapper = new ObjectMapper(); diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/JacksonCustomizations.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/JacksonCustomizations.java index 33a4558ad6..9cd6827dc5 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/JacksonCustomizations.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/JacksonCustomizations.java @@ -187,6 +187,7 @@ static abstract class MultiStatusMixin extends MultiStatus { "externalUrls", "setVendor", "setVendorId", + "setSpdxId", "setModifiedOn", "modifiedOn", "setModifiedBy", @@ -437,6 +438,7 @@ static abstract class ComponentMixin extends Component { "setComponentId", "setReleaseDate", "setExternalIds", + "setSpdxId", "externalToolProcessesSize", "setExternalToolProcesses", "setEccInformation", @@ -1001,7 +1003,8 @@ public static abstract class CommentMixin extends Comment { "setMainlineState", "setReleaseRelation", "setCreatedOn", - "setCreatedBy" + "setCreatedBy", + "setSpdxId" }) public static abstract class ProjectReleaseRelationshipMixin extends ProjectReleaseRelationship { } @@ -1098,7 +1101,8 @@ public static abstract class VulnerabilityMixinForCreateUpdate extends Vulnerabi "verificationStateInfoIterator", "setMatchedBy", "setUsedNeedle", - "setReleaseId" + "setReleaseId", + "setSpdxId" }) public static abstract class ReleaseVulnerabilityRelationMixin extends ReleaseVulnerabilityRelation { } @@ -1116,9 +1120,12 @@ public static abstract class VerificationStateInfoMixin extends VerificationStat @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties({ "setEnableSvm", - "setProjectRelationship" + "setProjectRelationship", + "setSpdxId" }) public static abstract class ProjectProjectRelationshipMixin extends ProjectProjectRelationship { } + + } }