From c4234b935766099a9a16a330420d79c4008acafa Mon Sep 17 00:00:00 2001 From: tuan99123 Date: Fri, 8 Apr 2022 14:56:17 +0700 Subject: [PATCH] feat(SPDX): Use new SPDX library (#1496) and release pages for showing SPDX/SPDX Lite data (#1240) Signed-off-by: tuan99123 --- backend/src-common/pom.xml | 13 + .../DocumentCreationInformationSummary.java | 43 + .../summary/FileInformationSummary.java | 43 + .../summary/PackageInformationSummary.java | 42 + .../summary/SpdxDocumentSummary.java | 43 + .../db/ChangeLogsDatabaseHandler.java | 1 - .../db/ComponentDatabaseHandler.java | 237 +++- .../datahandler/db/DatabaseHandlerUtil.java | 68 +- .../document/SpdxDocumentDatabaseHandler.java | 229 ++++ .../spdx/document/SpdxDocumentRepository.java | 45 + .../document/SpdxDocumentSearchHandler.java | 53 + ...dxDocumentCreationInfoDatabaseHandler.java | 196 +++ .../SpdxDocumentCreationInfoRepository.java | 45 + ...SpdxDocumentCreationInfoSearchHandler.java | 53 + .../SpdxPackageInfoDatabaseHandler.java | 250 ++++ .../SpdxPackageInfoRepository.java | 45 + .../SpdxPackageInfoSearchHandler.java | 53 + .../SpdxDocumentCreationInfoModerator.java | 162 +++ .../entitlement/SpdxDocumentModerator.java | 215 +++ .../entitlement/SpdxPackageInfoModerator.java | 213 +++ .../eclipse/sw360/spdx/SpdxBOMExporter.java | 281 ++++ .../sw360/spdx/SpdxBOMExporterSink.java | 66 + .../eclipse/sw360/spdx/SpdxBOMImporter.java | 652 ++++++++- .../sw360/spdx/SpdxBOMImporterSink.java | 98 +- .../sw360/spdx/SpdxBOMImporterTest.java | 2 +- backend/src/pom.xml | 3 + .../sw360/components/ComponentHandler.java | 19 +- .../fossology/rest/FossologyRestClient.java | 1 + .../sw360/licenseinfo/parsers/SPDXParser.java | 13 +- .../licenseinfo/parsers/SPDXParserTools.java | 65 +- .../licenseinfo/parsers/SPDXParserTest.java | 2 +- .../sw360/moderation/ModerationHandler.java | 51 + .../db/ModerationDatabaseHandler.java | 86 ++ .../db/ReleaseModerationRequestGenerator.java | 10 +- ...reationInfoModerationRequestGenerator.java | 55 + ...pdxDocumentModerationRequestGenerator.java | 56 + ...PackageInfoModerationRequestGenerator.java | 60 + backend/src/src-spdxdocument/pom.xml | 39 + .../spdxdocument/SPDXDocumentHandler.java | 95 ++ .../spdxdocument/SPDXDocumentServlet.java | 31 + .../src/src-spdxdocumentcreationinfo/pom.xml | 44 + .../DocumentCreationInformationHandler.java | 95 ++ .../DocumentCreationInformationServlet.java | 31 + backend/src/src-spdxpackageinfo/pom.xml | 44 + .../PackageInformationHandler.java | 107 ++ .../PackageInformationServlet.java | 31 + backend/svc/pom.xml | 3 + backend/svc/svc-spdxdocument/pom.xml | 73 + .../src/main/webapp/WEB-INF/web.xml | 38 + .../src/main/webapp/index.jsp | 23 + .../svc/svc-spdxdocumentcreationinfo/pom.xml | 73 + .../src/main/webapp/WEB-INF/web.xml | 38 + .../src/main/webapp/index.jsp | 23 + backend/svc/svc-spdxpackageinfo/pom.xml | 74 ++ .../src/main/webapp/WEB-INF/web.xml | 39 + .../src/main/webapp/index.jsp | 23 + .../portal/common/ChangeLogsPortletUtils.java | 60 +- .../sw360/portal/common/PortalConstants.java | 21 +- .../portlets/FossologyAwarePortlet.java | 2 +- .../sw360/portal/portlets/Sw360Portlet.java | 21 + .../portlets/components/ComponentPortlet.java | 569 ++++++-- .../portlets/components/spdx/SpdxPortlet.java | 420 ++++++ .../moderation/ModerationPortlet.java | 138 ++ .../portlets/projects/ProjectPortlet.java | 108 +- .../DisplayDocumentCreationInfoChanges.java | 307 +++++ .../tags/DisplayPackageInfoChanges.java | 365 +++++ .../tags/DisplaySPDXDocumentChanges.java | 481 +++++++ .../org/eclipse/sw360/portal/tags/OutTag.java | 10 + .../main/resources/META-INF/customTags.tld | 130 ++ .../resources/html/changelogs/elementView.jsp | 42 +- .../resources/html/components/edit.jsp | 3 +- .../resources/html/components/editRelease.jsp | 51 +- .../includes/releases/clearingDetails.jspf | 107 +- .../includes/releases/detailOverview.jspf | 106 +- .../includes/releases/spdx/edit.jspf | 596 +++++++++ .../spdx/includes/editAnnotations.jsp | 102 ++ .../editDocumentCreationInformation.jsp | 260 ++++ .../editOtherLicensingInformationDetected.jsp | 108 ++ .../spdx/includes/editPackageInformation.jsp | 498 +++++++ .../editRelationshipsBetweenSPDXElements.jsp | 71 + .../spdx/includes/editSnippetInformation.jsp | 200 +++ .../includes/releases/spdx/view.jsp | 1178 +++++++++++++++++ .../resources/html/components/view.jsp | 34 +- .../spdx/documentcreationinfo/delete.jsp | 93 ++ .../spdx/documentcreationinfo/merge.jsp | 102 ++ .../moderation/spdx/packageinfo/delete.jsp | 96 ++ .../moderation/spdx/packageinfo/merge.jsp | 105 ++ .../moderation/spdx/spdxdocument/delete.jsp | 92 ++ .../moderation/spdx/spdxdocument/merge.jsp | 101 ++ .../includes/projects/clearingStatus.jsp | 23 +- .../includes/projects/linkedObligations.jsp | 3 +- .../html/utils/ajax/linkedProjectsRows.jspf | 7 +- .../ajax/linkedReleasesClearingStatusRows.jsp | 7 +- .../html/utils/includes/importBom.jspf | 2 +- .../utils/includes/importBomForComponent.jspf | 315 +++++ .../html/utils/includes/scannerFindings.jspf | 88 ++ .../utils/includes/usingProjectsTable.jspf | 4 +- .../js/components/includes/releases/spdxjs.js | 1157 ++++++++++++++++ .../includes/releases/validateLib.js | 254 ++++ .../META-INF/resources/js/utils/array.js | 34 + .../resources/content/Language.properties | 43 +- .../resources/content/Language_ja.properties | 19 +- .../resources/content/Language_vi.properties | 24 +- .../datahandler/common/DatabaseSettings.java | 2 + .../sw360/datahandler/common/Moderator.java | 5 - .../datahandler/common/SW360Constants.java | 3 + .../sw360/datahandler/common/SW360Utils.java | 24 + .../datahandler/common/ThriftEnumUtils.java | 19 +- .../couchdb/DatabaseMixInForChangeLog.java | 131 ++ .../couchdb/DatabaseMixInForSPDXDocument.java | 226 ++++ .../permissions/ComponentPermissions.java | 3 - .../permissions/PermissionUtils.java | 9 + .../SpdxDocumentCreationInfoPermissions.java | 56 + .../permissions/SpdxDocumentPermissions.java | 56 + .../SpdxPackageInfoPermissions.java | 56 + .../datahandler/thrift/ThriftClients.java | 39 +- .../sw360/datahandler/thrift/ThriftUtils.java | 8 + .../datahandler/thrift/ThriftValidate.java | 30 + .../src/main/resources/sw360.properties | 4 - .../src/main/thrift/attachments.thrift | 5 +- .../src/main/thrift/changelogs.thrift | 8 +- .../src/main/thrift/components.thrift | 15 +- .../src/main/thrift/moderation.thrift | 55 + .../src/main/thrift/spdx/annotations.thrift | 21 + .../spdx/documentcreationinformation.thrift | 75 ++ .../main/thrift/spdx/fileinformation.thrift | 65 + .../otherlicensinginformationdetected.thrift | 21 + .../thrift/spdx/packageinformation.thrift | 92 ++ .../relationshipsbetweenspdxelements.thrift | 20 + .../thrift/spdx/snippetinformation.thrift | 34 + .../src/main/thrift/spdx/spdxdocument.thrift | 60 + .../src/main/thrift/sw360.thrift | 9 + .../changelog/ChangeLogController.java | 1 + 133 files changed, 13927 insertions(+), 275 deletions(-) create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/components/summary/DocumentCreationInformationSummary.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/components/summary/FileInformationSummary.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/components/summary/PackageInformationSummary.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/components/summary/SpdxDocumentSummary.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentDatabaseHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentRepository.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentSearchHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoDatabaseHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoRepository.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoSearchHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoDatabaseHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoRepository.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoSearchHandler.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentCreationInfoModerator.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentModerator.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxPackageInfoModerator.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporter.java create mode 100644 backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporterSink.java create mode 100644 backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentCreationInfoModerationRequestGenerator.java create mode 100644 backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentModerationRequestGenerator.java create mode 100644 backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxPackageInfoModerationRequestGenerator.java create mode 100644 backend/src/src-spdxdocument/pom.xml create mode 100644 backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentHandler.java create mode 100644 backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentServlet.java create mode 100644 backend/src/src-spdxdocumentcreationinfo/pom.xml create mode 100644 backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationHandler.java create mode 100644 backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationServlet.java create mode 100644 backend/src/src-spdxpackageinfo/pom.xml create mode 100644 backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationHandler.java create mode 100644 backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationServlet.java create mode 100644 backend/svc/svc-spdxdocument/pom.xml create mode 100644 backend/svc/svc-spdxdocument/src/main/webapp/WEB-INF/web.xml create mode 100644 backend/svc/svc-spdxdocument/src/main/webapp/index.jsp create mode 100644 backend/svc/svc-spdxdocumentcreationinfo/pom.xml create mode 100644 backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/WEB-INF/web.xml create mode 100644 backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/index.jsp create mode 100644 backend/svc/svc-spdxpackageinfo/pom.xml create mode 100644 backend/svc/svc-spdxpackageinfo/src/main/webapp/WEB-INF/web.xml create mode 100644 backend/svc/svc-spdxpackageinfo/src/main/webapp/index.jsp create mode 100644 frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/spdx/SpdxPortlet.java create mode 100644 frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayDocumentCreationInfoChanges.java create mode 100644 frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayPackageInfoChanges.java create mode 100644 frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplaySPDXDocumentChanges.java create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/edit.jspf create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editAnnotations.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editDocumentCreationInformation.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editOtherLicensingInformationDetected.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editPackageInformation.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editRelationshipsBetweenSPDXElements.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/includes/editSnippetInformation.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/components/includes/releases/spdx/view.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/documentcreationinfo/delete.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/documentcreationinfo/merge.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/delete.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/packageinfo/merge.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/delete.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/moderation/spdx/spdxdocument/merge.jsp create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/importBomForComponent.jspf create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/scannerFindings.jspf create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/spdxjs.js create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/js/components/includes/releases/validateLib.js create mode 100644 frontend/sw360-portlet/src/main/resources/META-INF/resources/js/utils/array.js create mode 100644 libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForSPDXDocument.java create mode 100644 libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentCreationInfoPermissions.java create mode 100644 libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentPermissions.java create mode 100644 libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxPackageInfoPermissions.java create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/annotations.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/documentcreationinformation.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/fileinformation.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/otherlicensinginformationdetected.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/packageinformation.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/relationshipsbetweenspdxelements.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/snippetinformation.thrift create mode 100644 libraries/lib-datahandler/src/main/thrift/spdx/spdxdocument.thrift 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..7c1ea886eb --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/DocumentCreationInformationSummary.java @@ -0,0 +1,43 @@ +/* + * 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.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +/** + * Created by HieuPV on 22/07/21. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..9b2b08968f --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/FileInformationSummary.java @@ -0,0 +1,43 @@ +/* + * 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.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.fileinformation.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +/** + * Created by HieuPV on 22/07/21. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..5037f3fb50 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/PackageInformationSummary.java @@ -0,0 +1,42 @@ +/* + * 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.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.*; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +/** + * Created by HieuPV on 22/07/21. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..870382f8d4 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/components/summary/SpdxDocumentSummary.java @@ -0,0 +1,43 @@ +/* + * 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.components.summary; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument; + +import static org.eclipse.sw360.datahandler.thrift.ThriftUtils.copyField; + +/** + * Created by HieuPV on 22/07/21. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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 d522197740..c0dec0aa0c 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 @@ -58,7 +58,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 f12137c5b8..aa965edaa0 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 { @@ -512,12 +530,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; } @@ -1669,6 +1701,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); dbHandlerUtil.addChangeLogs(null, release, user.getEmail(), Operation.DELETE, attachmentConnector, Lists.newArrayList(), null, null); @@ -2352,21 +2390,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 70172254cf..f71939e425 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; @@ -74,6 +76,7 @@ import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.ProjectReleaseRelationshipMixin; import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.RepositoryMixin; import org.eclipse.sw360.datahandler.couchdb.DatabaseMixInForChangeLog.VendorMixin; +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; @@ -98,6 +101,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 com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -122,6 +138,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; @@ -137,6 +154,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"); @@ -402,10 +420,23 @@ 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); } - log.info("Initialize ChangeLogs for Document Id : " + changeLog.getDocumentId()); - if (parentOperation != null) info.put("PARENT_OPERATION", parentOperation.name()); if (!info.isEmpty()) @@ -574,6 +605,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 { return; } @@ -598,6 +635,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 { return; } @@ -679,7 +722,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); } @@ -812,6 +855,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); } return mapper; } @@ -967,5 +1020,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..95753798b6 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentDatabaseHandler.java @@ -0,0 +1,229 @@ +/* + * 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.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; + +/** + * Class for accessing SPDXDocument information from the database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..a948506b60 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentRepository.java @@ -0,0 +1,45 @@ +/* + * 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.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; + +/** + * CRUD access for the SPDXDocument class + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..0be9e71ae6 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/document/SpdxDocumentSearchHandler.java @@ -0,0 +1,53 @@ +/* + * 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.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; + +/** + * Class for accessing the Lucene connector on the CouchDB database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..ebfb0d531a --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoDatabaseHandler.java @@ -0,0 +1,196 @@ +/* + * 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.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; + +/** + * Class for accessing SPDX Document Creation Information from the database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..460eb21589 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoRepository.java @@ -0,0 +1,45 @@ +/* + * 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.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; + +/** + * CRUD access for the DocumentCreationInformation class + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..c3c47cd43b --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/documentcreationinfo/SpdxDocumentCreationInfoSearchHandler.java @@ -0,0 +1,53 @@ +/* + * 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.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; + +/** + * Class for accessing the Lucene connector on the CouchDB database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..96752a94c2 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoDatabaseHandler.java @@ -0,0 +1,250 @@ +/* + * 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.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; + +/** + * Class for accessing SPDX Package Information from the database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..91a3a343c3 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoRepository.java @@ -0,0 +1,45 @@ +/* + * 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.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; + +/** + * CRUD access for the PackageInformation class + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..03b65fadc5 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/spdx/packageinfo/SpdxPackageInfoSearchHandler.java @@ -0,0 +1,53 @@ +/* + * 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.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; + +/** + * Class for accessing the Lucene connector on the CouchDB database + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..2c362a1605 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentCreationInfoModerator.java @@ -0,0 +1,162 @@ +/* + * 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.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; + +/** + * Moderation for the SPDX DocumentCreationInformation service + * + * @author hieu1.phamvan@toshiba.co.jp + */ + +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..3795fec517 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxDocumentModerator.java @@ -0,0 +1,215 @@ +/* + * 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.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; + +/** + * Moderation for the SPDX Document service + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..ef55f79886 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/entitlement/SpdxPackageInfoModerator.java @@ -0,0 +1,213 @@ +/* + * 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.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; + +/** + * Moderation for the SPDX PackageInformation service + * + * @author hieu1.phamvan@toshiba.co.jp + */ + +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..a9ae807b94 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporter.java @@ -0,0 +1,281 @@ +/* + * 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.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..177fe1f056 --- /dev/null +++ b/backend/src-common/src/main/java/org/eclipse/sw360/spdx/SpdxBOMExporterSink.java @@ -0,0 +1,66 @@ +/* + * 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.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..a75333bf71 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,13 @@ 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]; + } } 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..8d00129808 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 @@ -83,7 +83,7 @@ public void testProject() throws Exception { @Test public void testRelease() throws Exception { - final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsRelease(inputStream, attachmentContent); + final RequestSummary requestSummary = spdxBOMImporter.importSpdxBOMAsRelease(inputStream, attachmentContent, null, null); 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 684d1e29ca..7b2634d24c 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 @@ -617,10 +617,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 90a003fdcb..7eb6276970 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 @@ -215,6 +215,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-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParser.java b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParser.java index 23fd02cba0..98ece9a9da 100644 --- a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParser.java +++ b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParser.java @@ -15,6 +15,7 @@ import org.eclipse.sw360.datahandler.thrift.SW360Exception; 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.licenseinfo.LicenseInfoParsingResult; import org.eclipse.sw360.datahandler.thrift.licenseinfo.LicenseInfoRequestStatus; import org.eclipse.sw360.datahandler.thrift.users.User; @@ -60,16 +61,16 @@ public List getApplicableFileExtensions() { @Override public List getLicenseInfos(Attachment attachment, User user, T context) throws TException { - return Collections.singletonList(getLicenseInfo(attachment, true, user, context)); + return Collections.singletonList(getLicenseInfo(attachment, true, false, user, context)); } @Override public List getLicenseInfosIncludeConcludedLicense(Attachment attachment, boolean includeConcludedLicense, User user, T context) throws TException { - return Collections.singletonList(getLicenseInfo(attachment, includeConcludedLicense, user, context)); + return Collections.singletonList(getLicenseInfo(attachment, includeConcludedLicense, false, user, context)); } - public LicenseInfoParsingResult getLicenseInfo(Attachment attachment, boolean includeConcludedLicense, User user, + public LicenseInfoParsingResult getLicenseInfo(Attachment attachment, boolean includeConcludedLicense, boolean includeFileInformation, User user, T context) throws TException { AttachmentContent attachmentContent = attachmentContentProvider.getAttachmentContent(attachment); @@ -78,8 +79,10 @@ public LicenseInfoParsingResult getLicenseInfo(Attachment attachment, boolea return new LicenseInfoParsingResult() .setStatus(LicenseInfoRequestStatus.FAILURE); } - - return getLicenseInfoFromSpdx(attachmentContent, includeConcludedLicense, spdxDocument.get()); + if (attachment.getAttachmentType().equals(AttachmentType.INITIAL_SCAN_REPORT)) { + return getLicenseInfoFromSpdx(attachmentContent, includeConcludedLicense, true, spdxDocument.get()); + } + return getLicenseInfoFromSpdx(attachmentContent, includeConcludedLicense, false, spdxDocument.get()); } protected String getUriOfAttachment(AttachmentContent attachmentContent) throws URISyntaxException { diff --git a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTools.java b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTools.java index 6a810b3e0f..6d7b39e9dc 100644 --- a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTools.java +++ b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTools.java @@ -35,6 +35,7 @@ import org.apache.jena.rdf.model.impl.Util; +import static org.eclipse.sw360.datahandler.common.CommonUtils.isNotNullEmptyOrWhitespace; import static org.eclipse.sw360.datahandler.common.CommonUtils.isNullEmptyOrWhitespace; public class SPDXParserTools { @@ -57,6 +58,7 @@ public class SPDXParserTools { // SPDX Class private static final String SPDX_FILE = "File"; + private static final String SPDX_FILE_NAME = "fileName"; private static final String SPDX_LICENSE = "License"; private static final String SPDX_PACKAGE = "Package"; private static final String SPDX_EXTRACTED_LICENSING_INFO = "ExtractedLicensingInfo"; @@ -324,11 +326,20 @@ private static Node getLicenseDeclared(Node spdxPackage) { return licenseDeclareds.length > 0 ? licenseDeclareds[0] : null; } + private static LicenseNameWithText getLicenseObject(Element e) { + String licenseName = extractLicenseName(e); + String licenseID = getLicenseId(e); + String licenseText = getExtractedText(e); + if (isNullEmptyOrWhitespace(licenseText)) { + licenseText = getLicenseText(e); + } + return new LicenseNameWithText().setLicenseName(licenseName).setLicenseText(licenseText).setLicenseSpdxId(licenseID); + } /* * Get all licenses with text in spdx:ExtractedLicensingInfo and spdx:License * with their uri. */ - private static HashMap getLicenseTextFromMetadata(Document doc) { + private static HashMap getLicenseTextFromMetadata(Document doc, boolean includeFileInformation) { HashMap uriLicenseMap = new HashMap(); String[] licenseTags = { SPDX_EXTRACTED_LICENSING_INFO, SPDX_LICENSE }; @@ -346,17 +357,49 @@ private static HashMap getLicenseTextFromMetadata(D if (isNullEmptyOrWhitespace(uri)) continue; - String licenseName = extractLicenseName(e); - String licenseID = getLicenseId(e); - String licenseText = getExtractedText(e); - if (isNullEmptyOrWhitespace(licenseText)) - licenseText = getLicenseText(e); - uriLicenseMap.put(uri, new LicenseNameWithText().setLicenseName(licenseName) - .setLicenseText(licenseText).setLicenseSpdxId(licenseID)); + uriLicenseMap.put(uri, getLicenseObject(e)); + } + } + } + if (includeFileInformation) { + Node[] files = findMultipleSpdxNodes(doc, SPDX_FILE); + // To link license with files -> adding source files into LicenseNameWithText + for (Node file : files) { + NodeList childNodes = file.getChildNodes(); + String sourceFileName = ""; + for (Node child : iterable(childNodes)) { + if (isNotNullEmptyOrWhitespace(child.getLocalName())) { + if (child.getLocalName().equals(SPDX_FILE_NAME)) { + sourceFileName = child.getTextContent(); + } else if (child.getLocalName().equals(SPDX_LICENSE_INFO_IN_FILE)) { + if (child instanceof Element) { + Element e = (Element) child; + String uri = e.getAttributeNS(RDF_NAMESPACE, RDF_RESOURCE); + + if (isNullEmptyOrWhitespace(uri)) { + continue; + } + LicenseNameWithText lnwt = uriLicenseMap.containsKey(uri) ? uriLicenseMap.get(uri) : getLicenseObject(e); + lnwt.addToSourceFiles(sourceFileName); + uriLicenseMap.put(uri, lnwt); + } + } else if (child.getLocalName().equals(SPDX_LICENSE_CONCLUDED)) { + if (child instanceof Element) { + Element e = (Element) child; + String uri = e.getAttributeNS(RDF_NAMESPACE, RDF_RESOURCE); + + if (isNullEmptyOrWhitespace(uri)) { + continue; + } + LicenseNameWithText lnwt = uriLicenseMap.containsKey(uri) ? uriLicenseMap.get(uri) : getLicenseObject(e); + lnwt.addToSourceFiles(sourceFileName); + uriLicenseMap.put(uri, lnwt); + } + } + } } } } - return uriLicenseMap; } @@ -607,13 +650,13 @@ private static Stream getAllCopyrights(Node spdxItem) { } protected static LicenseInfoParsingResult getLicenseInfoFromSpdx(AttachmentContent attachmentContent, - boolean includeConcludedLicense, Document doc) { + boolean includeConcludedLicense, boolean includeFileInformation, Document doc) { LicenseInfo licenseInfo = new LicenseInfo().setFilenames(Arrays.asList(attachmentContent.getFilename())); licenseInfo.setLicenseNamesWithTexts(new HashSet<>()); licenseInfo.setCopyrights(new HashSet<>()); Set concludedLicenseIds = Sets.newHashSet(); - uriLicenseMap = getLicenseTextFromMetadata(doc); + uriLicenseMap = getLicenseTextFromMetadata(doc, includeFileInformation); nodeIDFileMap = getFileFromMetadata(doc); for (Node spdxItem : getDocumentDescribes(doc)) { diff --git a/backend/src/src-licenseinfo/src/test/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTest.java b/backend/src/src-licenseinfo/src/test/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTest.java index 08b38a1916..56cdb17aab 100644 --- a/backend/src/src-licenseinfo/src/test/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTest.java +++ b/backend/src/src-licenseinfo/src/test/java/org/eclipse/sw360/licenseinfo/parsers/SPDXParserTest.java @@ -139,7 +139,7 @@ public void testAddSPDXContentToCLI(String exampleFile, List expectedLic Document spdxDocument = dBuilder.parse(input); spdxDocument.getDocumentElement().normalize(); - LicenseInfoParsingResult result = SPDXParserTools.getLicenseInfoFromSpdx(attachmentContent, true, spdxDocument); + LicenseInfoParsingResult result = SPDXParserTools.getLicenseInfoFromSpdx(attachmentContent, true, false, spdxDocument); assertIsResultOfExample(result.getLicenseInfo(), exampleFile, expectedLicenses, numberOfCoyprights, exampleCopyright, exampleConcludedLicenseIds); } 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..cb9d379b37 --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentCreationInfoModerationRequestGenerator.java @@ -0,0 +1,55 @@ +/* + * 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.moderation.db; + +import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.DocumentCreationInformation; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; + +/** + * Class for comparing a document with its counterpart in the database + * Writes the difference (= additions and deletions) to the moderation request + * + * @author hieu1.phamvan@toshiba.co.jp + */ + +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..c69470d7b8 --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxDocumentModerationRequestGenerator.java @@ -0,0 +1,56 @@ +/* + * 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.moderation.db; + +import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.*; +import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest; + +/** + * Class for comparing a document with its counterpart in the database + * Writes the difference (= additions and deletions) to the moderation request + * + * @author hieu1.phamvan@toshiba.co.jp + */ + +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..2933674f1b --- /dev/null +++ b/backend/src/src-moderation/src/main/java/org/eclipse/sw360/moderation/db/SpdxPackageInfoModerationRequestGenerator.java @@ -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 + */ +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; + +/** + * Class for comparing a document with its counterpart in the database + * Writes the difference (= additions and deletions) to the moderation request + * + * @author hieu1.phamvan@toshiba.co.jp + */ + +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..bff06e891e --- /dev/null +++ b/backend/src/src-spdxdocument/pom.xml @@ -0,0 +1,39 @@ + + + + 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..cbd01d6874 --- /dev/null +++ b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentHandler.java @@ -0,0 +1,95 @@ +/* + * 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.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.*; + +/** + * Implementation of the Thrift service + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..3dff4b9683 --- /dev/null +++ b/backend/src/src-spdxdocument/src/main/java/org/eclipse/sw360/spdxdocument/SPDXDocumentServlet.java @@ -0,0 +1,31 @@ +/* + * 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.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; + +/** + * Thrift Servlet instantiation + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..c4a3250215 --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/pom.xml @@ -0,0 +1,44 @@ + + + + 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..69a05ad27a --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationHandler.java @@ -0,0 +1,95 @@ +/* + * 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.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.*; + +/** + * Implementation of the Thrift service + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..1700a5ec1f --- /dev/null +++ b/backend/src/src-spdxdocumentcreationinfo/src/main/java/org/eclipse/sw360/spdxdocumentcreationinfo/DocumentCreationInformationServlet.java @@ -0,0 +1,31 @@ +/* + * 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.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; + +/** + * Thrift Servlet instantiation + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..63f1c302a1 --- /dev/null +++ b/backend/src/src-spdxpackageinfo/pom.xml @@ -0,0 +1,44 @@ + + + + 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..3fd31eb010 --- /dev/null +++ b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationHandler.java @@ -0,0 +1,107 @@ +/* + * 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.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.*; + +/** + * Implementation of the Thrift service + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..080c5b8aac --- /dev/null +++ b/backend/src/src-spdxpackageinfo/src/main/java/org/eclipse/sw360/spdxpackageinfo/PackageInformationServlet.java @@ -0,0 +1,31 @@ +/* + * 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.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; + +/** + * Thrift Servlet instantiation + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..ff6d1a37c9 --- /dev/null +++ b/backend/svc/svc-spdxdocument/pom.xml @@ -0,0 +1,73 @@ + + + + 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..d523767be0 --- /dev/null +++ b/backend/svc/svc-spdxdocument/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,38 @@ + + + + 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..5ee91cfd26 --- /dev/null +++ b/backend/svc/svc-spdxdocument/src/main/webapp/index.jsp @@ -0,0 +1,23 @@ + +<%@ 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..b5924e9bc3 --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/pom.xml @@ -0,0 +1,73 @@ + + + + 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..924067d4fe --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,38 @@ + + + + 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..0675354785 --- /dev/null +++ b/backend/svc/svc-spdxdocumentcreationinfo/src/main/webapp/index.jsp @@ -0,0 +1,23 @@ + +<%@ 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..6c91775eef --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/pom.xml @@ -0,0 +1,74 @@ + + + + 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..1b518e745a --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,39 @@ + + + + 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..db531ba332 --- /dev/null +++ b/backend/svc/svc-spdxpackageinfo/src/main/webapp/index.jsp @@ -0,0 +1,23 @@ + +<%@ 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/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 f8b4a53c35..e50e51defb 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 @@ -65,6 +65,8 @@ public class PortalConstants { //! Standard keys for Lists and their size public static final String KEY_SUMMARY = "documents"; + public static final String RDF_FILE_EXTENSION = ".rdf"; + public static final String XML_FILE_EXTENSION = ".xml"; public static final String KEY_LIST_SIZE = "documentssize"; @@ -113,6 +115,7 @@ public class PortalConstants { public static final String LICENSE_TYPE_GLOBAL = "global"; public static final String LICENSE_TYPE_OTHERS = "Others"; public static final String LICENSE_IDS = "licenseIds"; + public static final String MAIN_LICENSE_FILES = "LICENSE.*|license|license.txt|license.html|COPYING.*|copying|copying.txt|copying.html"; //! Specialized keys for moderation public static final String MODERATION_PORTLET_NAME = PORTLET_NAME_PREFIX + "moderations"; @@ -297,7 +300,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"; @@ -493,7 +495,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"; @@ -649,6 +655,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); @@ -687,6 +705,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/FossologyAwarePortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/FossologyAwarePortlet.java index cb498d2fb6..257479970e 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/FossologyAwarePortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/FossologyAwarePortlet.java @@ -122,7 +122,7 @@ protected void serveLicenseToSourceFileMapping(ResourceRequest request, Resource Predicate isApprovedCLI = attachment -> CheckStatus.ACCEPTED.equals(attachment.getCheckStatus()); filteredAttachments = filteredAttachments.stream().filter(isApprovedCLI).collect(Collectors.toList()); } - if (filteredAttachments.size() == 1 && filteredAttachments.get(0).getFilename().endsWith(".xml")) { + if (filteredAttachments.size() == 1 && filteredAttachments.get(0).getFilename().endsWith(PortalConstants.XML_FILE_EXTENSION)) { final Attachment filteredAttachment = filteredAttachments.get(0); final String attachmentContentId = filteredAttachment.getAttachmentContentId(); 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 fe5abb9ce5..de18c3aebf 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,6 +12,7 @@ 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.collect.ImmutableList; @@ -58,11 +59,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; @@ -71,10 +77,12 @@ import org.apache.thrift.TEnum; import org.apache.thrift.TException; import org.apache.thrift.TSerializer; -import org.apache.thrift.protocol.TSimpleJSONProtocol; 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 +109,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 +190,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 +221,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); @@ -225,10 +237,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)) { @@ -237,8 +253,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."); } } @@ -262,13 +325,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); @@ -283,6 +361,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 { @@ -392,7 +507,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()); @@ -573,35 +688,54 @@ private void loadSpdxLicenseInfo(ResourceRequest request, ResourceResponse respo String releaseId = request.getParameter(PortalConstants.RELEASE_ID); String attachmentContentId = request.getParameter(PortalConstants.ATTACHMENT_ID); String attachmentName = request.getParameter(PortalConstants.ATTACHMENT_NAME); + Map> licenseToSrcFilesMap = new LinkedHashMap<>(); boolean includeConcludedLicense = new Boolean(request.getParameter(PortalConstants.INCLUDE_CONCLUDED_LICENSE)); ComponentService.Iface componentClient = thriftClients.makeComponentClient(); LicenseInfoService.Iface licenseInfoClient = thriftClients.makeLicenseInfoClient(); - Set concludedLicenseIds = new HashSet<>(); - Set mainLicenseNames = new HashSet(); - Set otherLicenseNames = new HashSet(); + final Set concludedLicenseIds = new TreeSet(); + Set mainLicenseNames = new TreeSet(); + Set otherLicenseNames = new TreeSet(); + AttachmentType attachmentType = AttachmentType.OTHER; + long totalFileCount = 0; try { Release release = componentClient.getReleaseById(releaseId, user); List licenseInfoResult = licenseInfoClient.getLicenseInfoForAttachment(release, attachmentContentId, includeConcludedLicense, user); + attachmentType = release.getAttachments().stream().filter(att -> attachmentContentId.equals(att.getAttachmentContentId())).map(Attachment::getAttachmentType).findFirst().orElse(null); List licenseWithTexts = licenseInfoResult.stream() .flatMap(result -> result.getLicenseInfo().getLicenseNamesWithTexts().stream()) .filter(license -> !license.getLicenseName().equalsIgnoreCase(SW360Constants.LICENSE_NAME_UNKNOWN) && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NA) && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NO_ASSERTION)) // exclude unknown, n/a and noassertion .collect(Collectors.toList()); - if (attachmentName.endsWith(".rdf")) { - concludedLicenseIds = licenseInfoResult.stream() - .flatMap(singleResult -> singleResult.getLicenseInfo().getConcludedLicenseIds().stream()) - .collect(Collectors.toSet()); - otherLicenseNames = licenseWithTexts.stream().map(LicenseNameWithText::getLicenseName).collect(Collectors.toSet()); + + if (attachmentName.endsWith(PortalConstants.RDF_FILE_EXTENSION)) { + if (AttachmentType.INITIAL_SCAN_REPORT.equals(attachmentType)) { + totalFileCount = licenseWithTexts.stream().map(LicenseNameWithText::getSourceFiles).filter(src -> src != null).mapToInt(Set::size).sum(); + licenseToSrcFilesMap = licenseWithTexts.stream().collect(Collectors.toMap(LicenseNameWithText::getLicenseName, + LicenseNameWithText::getSourceFiles, (oldValue, newValue) -> oldValue)); + licenseWithTexts.forEach(lwt -> { + lwt.getSourceFiles().forEach(sf -> { + if (sf.replaceAll(".*/", "").matches(MAIN_LICENSE_FILES)) { + concludedLicenseIds.add(lwt.getLicenseName()); + } + }); + }); + } else { + concludedLicenseIds.addAll(licenseInfoResult.stream().flatMap(singleResult -> singleResult.getLicenseInfo().getConcludedLicenseIds().stream()).collect(Collectors.toCollection(TreeSet::new))); + } + otherLicenseNames = licenseWithTexts.stream().map(LicenseNameWithText::getLicenseName).collect(Collectors.toCollection(TreeSet::new)); otherLicenseNames.removeAll(concludedLicenseIds); - } else if (attachmentName.endsWith(".xml")) { - mainLicenseNames = licenseWithTexts.stream().filter(license -> license.getType().equals(LICENSE_TYPE_GLOBAL)).map(LicenseNameWithText::getLicenseName).collect(Collectors.toSet()); - otherLicenseNames = licenseWithTexts.stream().filter(license -> !license.getType().equals(LICENSE_TYPE_GLOBAL)).map(LicenseNameWithText::getLicenseName).collect(Collectors.toSet()); + } else if (attachmentName.endsWith(PortalConstants.XML_FILE_EXTENSION)) { + mainLicenseNames = licenseWithTexts.stream() + .filter(license -> license.getType().equals(LICENSE_TYPE_GLOBAL)) + .map(LicenseNameWithText::getLicenseName).collect(Collectors.toCollection(TreeSet::new)); + otherLicenseNames = licenseWithTexts.stream() + .filter(license -> !license.getType().equals(LICENSE_TYPE_GLOBAL)) + .map(LicenseNameWithText::getLicenseName).collect(Collectors.toCollection(TreeSet::new)); } - } catch (TException e) { log.error("Cannot retrieve license information for attachment id " + attachmentContentId + " in release " + releaseId + ".", e); @@ -612,21 +746,35 @@ 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.id")); + jsonGenerator.writeStringField("otherLicense", LanguageUtil.get(resourceBundle, "other.license.id")); 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")); + jsonGenerator.writeStringField("totalFileCount", Long.toString(totalFileCount)); + } + for (Map.Entry> entry : licenseToSrcFilesMap.entrySet()) { + jsonGenerator.writeArrayFieldStart(entry.getKey()); + entry.getValue().forEach(srcFile -> wrapException(() -> { jsonGenerator.writeString(srcFile); })); + jsonGenerator.writeEndArray(); + } jsonGenerator.writeEndObject(); jsonGenerator.close(); @@ -640,6 +788,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; @@ -667,6 +816,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"); @@ -763,7 +914,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")); } } } @@ -785,7 +936,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); @@ -805,10 +959,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); @@ -818,7 +992,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")); } } @@ -842,7 +1016,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; @@ -860,6 +1068,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); @@ -993,7 +1267,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()); @@ -1037,7 +1311,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(); @@ -1063,7 +1337,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."); @@ -1171,11 +1445,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()); @@ -1205,15 +1479,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; } @@ -1221,7 +1495,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(); @@ -1229,17 +1503,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()); } @@ -1248,11 +1522,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 @@ -1266,7 +1540,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); @@ -1292,7 +1566,7 @@ private Map getUsageInformationForReleaseMerge(String releaseSo usageInformation.put("releaseVulnerabilities", releaseVulnerabilities.size()); List projectRatings = vulnerabilityClient.getProjectVulnerabilityRatingsByReleaseId(releaseSourceId, sessionUser); usageInformation.put("projectRatings", projectRatings.size()); - + return usageInformation; } @@ -1306,7 +1580,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(); @@ -1333,7 +1607,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."); @@ -1471,7 +1745,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(); @@ -1492,6 +1766,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) { @@ -1511,7 +1840,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(); @@ -1525,7 +1854,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; @@ -1544,14 +1873,22 @@ private String createFossologyJobViewLink(ExternalToolProcessStep processStep, private void setSpdxAttachmentsInRequest(RenderRequest request, Release release) { Set attachments = CommonUtils.nullToEmptySet(release.getAttachments()); - Set spdxAttachments = attachments.stream() - .filter(a -> AttachmentType.COMPONENT_LICENSE_INFO_COMBINED.equals(a.getAttachmentType()) - || AttachmentType.COMPONENT_LICENSE_INFO_XML.equals(a.getAttachmentType())) - .collect(Collectors.toSet()); + Set attTypes = attachments.stream().map(Attachment::getAttachmentType).collect(Collectors.toUnmodifiableSet()); + Set spdxAttachments = Sets.newHashSet(); + if (attTypes.contains(AttachmentType.COMPONENT_LICENSE_INFO_COMBINED) || attTypes.contains(AttachmentType.COMPONENT_LICENSE_INFO_XML)) { + spdxAttachments = attachments.stream() + .filter(a -> AttachmentType.COMPONENT_LICENSE_INFO_COMBINED.equals(a.getAttachmentType()) + || AttachmentType.COMPONENT_LICENSE_INFO_XML.equals(a.getAttachmentType())) + .collect(Collectors.toSet()); + } else if (attTypes.contains(AttachmentType.INITIAL_SCAN_REPORT)) { + spdxAttachments = attachments.stream() + .filter(a -> AttachmentType.INITIAL_SCAN_REPORT.equals(a.getAttachmentType())) + .collect(Collectors.toSet()); + } 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(), @@ -1572,7 +1909,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) { @@ -1592,14 +1929,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 { @@ -1618,7 +1955,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(); @@ -1636,8 +1973,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); @@ -1796,7 +2133,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); @@ -1820,7 +2157,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); @@ -1889,7 +2226,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); @@ -1918,6 +2255,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(); @@ -1937,8 +2275,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); @@ -1978,7 +2337,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); @@ -2025,7 +2384,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..09df2a0722 --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/components/spdx/SpdxPortlet.java @@ -0,0 +1,420 @@ +/* + * 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; + +/** + * SPDX portlet implementation + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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 ff03150805..c2df5efd66 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; @@ -596,6 +602,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; } } @@ -765,6 +807,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; } } } @@ -998,6 +1049,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 97465049d7..62808cea64 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 @@ -95,6 +95,7 @@ import static org.eclipse.sw360.datahandler.common.CommonUtils.*; import static org.eclipse.sw360.datahandler.common.SW360Constants.CONTENT_TYPE_OPENXML_SPREADSHEET; import static org.eclipse.sw360.datahandler.common.SW360Utils.printName; +import static org.eclipse.sw360.datahandler.common.WrappedException.wrapException; import static org.eclipse.sw360.datahandler.common.WrappedException.wrapTException; import static org.eclipse.sw360.portal.common.PortalConstants.*; import static org.eclipse.sw360.portal.portlets.projects.ProjectPortletUtils.isUsageEquivalent; @@ -244,6 +245,8 @@ public void serveResource(ResourceRequest request, ResourceResponse response) th serveLicenseToSourceFileMapping(request, response); } else if (PortalConstants.ADD_LICENSE_TO_RELEASE.equals(action)) { addLicenseToLinkedReleases(request, response); + } else if (PortalConstants.LOAD_SPDX_LICENSE_INFO.equals(action)) { + loadSpdxLicenseInfo(request, response); } else if (isGenericAction(action)) { dealWithGenericAction(request, response, action); } else if (PortalConstants.LOAD_CHANGE_LOGS.equals(action) || PortalConstants.VIEW_CHANGE_LOGS.equals(action)) { @@ -2583,8 +2586,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) { @@ -2627,17 +2628,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; } @@ -2706,14 +2698,14 @@ private void addLicenseToLinkedReleases(ResourceRequest request, ResourceRespons && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NA) && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NO_ASSERTION)) // exclude unknown, n/a and noassertion .collect(Collectors.toList()); - if (attachmentName.endsWith(".rdf")) { + if (attachmentName.endsWith(PortalConstants.RDF_FILE_EXTENSION)) { mainLicenses.addAll(licenseInfoResult.stream() .filter(filterConcludedLicense) .flatMap(singleResult -> singleResult.getLicenseInfo().getConcludedLicenseIds().stream()) .collect(Collectors.toSet())); otherLicenses.addAll(licenseWithTexts.stream().map(LicenseNameWithText::getLicenseName).collect(Collectors.toSet())); otherLicenses.removeAll(mainLicenses); - } else if (attachmentName.endsWith(".xml")) { + } else if (attachmentName.endsWith(PortalConstants.XML_FILE_EXTENSION)) { mainLicenses.addAll(licenseWithTexts.stream() .filter(filterLicense) .map(LicenseNameWithText::getLicenseName).collect(Collectors.toSet())); @@ -2746,6 +2738,92 @@ private void addLicenseToLinkedReleases(ResourceRequest request, ResourceRespons } } + private void loadSpdxLicenseInfo(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { + final User user = UserCacheHolder.getUserFromRequest(request); + final String releaseId = request.getParameter(PortalConstants.RELEASE_ID); + final ComponentService.Iface componentClient = thriftClients.makeComponentClient(); + final LicenseInfoService.Iface licenseInfoClient = thriftClients.makeLicenseInfoClient(); + final JSONObject jsonResult = createJSONObject(); + final ResourceBundle resourceBundle = ResourceBundleUtil.getBundle("content.Language", request.getLocale(), getClass()); + final Predicate isISR = attachment -> AttachmentType.INITIAL_SCAN_REPORT.equals(attachment.getAttachmentType()); + + Set licenseNameWithTexts = new HashSet(); + String attachmentContentId = ""; + String attachmentName = ""; + Set concludedLicenseIds = new TreeSet(); + Set otherLicenseNames = new TreeSet(); + AttachmentType attachmentType = AttachmentType.OTHER; + long totalFileCount = 0; + try { + Release release = componentClient.getReleaseById(releaseId, user); + Set attachments = CommonUtils.nullToEmptySet(release.getAttachments()); + attachments = attachments.stream().filter(isISR).collect(Collectors.toSet()); + if (attachments.size() == 1) { + Attachment attachment = attachments.iterator().next(); + attachmentType = attachment.getAttachmentType(); + attachmentContentId = attachment.getAttachmentContentId(); + attachmentName = attachment.getFilename(); + List licenseInfoResult = licenseInfoClient.getLicenseInfoForAttachment(release, + attachmentContentId, true, user); + List licenseWithTexts = licenseInfoResult.stream() + .flatMap(result -> result.getLicenseInfo().getLicenseNamesWithTexts().stream()) + .filter(license -> !license.getLicenseName().equalsIgnoreCase(SW360Constants.LICENSE_NAME_UNKNOWN) + && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NA) + && !license.getLicenseName().equalsIgnoreCase(SW360Constants.NO_ASSERTION)) // exclude unknown, n/a and noassertion + .collect(Collectors.toList()); + if (attachmentName.endsWith(PortalConstants.RDF_FILE_EXTENSION)) { + totalFileCount = licenseWithTexts.stream().map(LicenseNameWithText::getSourceFiles).filter(src -> src != null).mapToInt(Set::size).sum(); + concludedLicenseIds = licenseInfoResult.stream() + .flatMap(singleResult -> singleResult.getLicenseInfo().getConcludedLicenseIds().stream()) + .collect(Collectors.toCollection(TreeSet::new)); + otherLicenseNames = licenseWithTexts.stream().map(LicenseNameWithText::getLicenseName) + .collect(Collectors.toCollection(TreeSet::new)); + otherLicenseNames.removeAll(concludedLicenseIds); + } + } else { + jsonResult.put(SW360Constants.STATUS, SW360Constants.FAILURE); + if (attachments.size() > 1) { + jsonResult.put(SW360Constants.MESSAGE, LanguageUtil.get(resourceBundle, "multiple.isr.are.found.in.the.release")); + } else if (attachments.isEmpty()) { + jsonResult.put(SW360Constants.MESSAGE, LanguageUtil.get(resourceBundle, "isr.attachment.not.found.in.the.release")); + } else { + jsonResult.put(SW360Constants.MESSAGE, LanguageUtil.get(resourceBundle, "license.information.not.found.in.isr")); + } + } + } catch (TException e) { + log.error("Cannot retrieve license information for attachment id " + attachmentContentId + " in release " + + releaseId + ".", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, "500"); + } + + try { + JsonGenerator jsonGenerator = JSON_FACTORY.createGenerator(response.getWriter()); + jsonGenerator.writeStartObject(); + if (concludedLicenseIds.size() > 0) { + jsonGenerator.writeStringField(LICENSE_PREFIX, LanguageUtil.get(resourceBundle,"concluded.license.ids")); + jsonGenerator.writeArrayFieldStart(LICENSE_IDS); + concludedLicenseIds.forEach(licenseId -> wrapException(() -> { jsonGenerator.writeString(licenseId); })); + jsonGenerator.writeEndArray(); + } + jsonGenerator.writeStringField("otherLicense", LanguageUtil.get(resourceBundle,"other.license.id")); + jsonGenerator.writeArrayFieldStart("otherLicenseIds"); + 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")); + jsonGenerator.writeStringField("totalFileCount", Long.toString(totalFileCount)); + jsonGenerator.writeStringField("fileName", attachmentName); + } + jsonGenerator.writeStringField(SW360Constants.STATUS, SW360Constants.SUCCESS); + jsonGenerator.writeEndObject(); + jsonGenerator.close(); + } catch (IOException | RuntimeException e) { + log.error("Cannot write JSON response for attachment id " + attachmentContentId + " in release " + releaseId + + ".", e); + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, "500"); + } + } + private void serveClearingStatusList(ResourceRequest request, ResourceResponse response) { ProjectService.Iface client = thriftClients.makeProjectClient(); User user = UserCacheHolder.getUserFromRequest(request); 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..d1f2ba4a28 --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayDocumentCreationInfoChanges.java @@ -0,0 +1,307 @@ +/* + * 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.*; + +/** + * Display the fields that have changed in the SPDX Document Creation Info + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..118d7bf1fb --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplayPackageInfoChanges.java @@ -0,0 +1,365 @@ +/* + * 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.*; + +/** + * Display the fields that have changed in the SPDX Package Info + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..e25cdac7e3 --- /dev/null +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/tags/DisplaySPDXDocumentChanges.java @@ -0,0 +1,481 @@ +/* + * 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.*; + +/** + * Display the fields that have changed in the SPDX Document + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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 dd63106bad..a62d131f37 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 @@ -167,23 +167,23 @@
    - + + +
    +
    + + +
    +
    +
    (${totalRows})"> (${totalRows})
    @@ -204,7 +204,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/clearingStatus.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/clearingStatus.jsp index 6172174755..70aeef47c5 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/clearingStatus.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/projects/includes/projects/clearingStatus.jsp @@ -40,6 +40,10 @@ + + + + @@ -147,6 +151,7 @@ <%--for javascript library loading --%> <%@ include file="/html/utils/includes/requirejs.jspf" %> <%@ include file="/html/utils/includes/licenseToSrcMapping.jspf" %> +<%@ include file="/html/utils/includes/scannerFindings.jspf" %> diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/scannerFindings.jspf b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/scannerFindings.jspf new file mode 100644 index 0000000000..bed2c7132a --- /dev/null +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/scannerFindings.jspf @@ -0,0 +1,88 @@ +<%-- + ~ Copyright Siemens AG, 2022. Part of the SW360 Portal Project. + ~ With contributions by Siemens Healthcare Diagnostics Inc, 2022. + ~ + ~ 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 + --%> + diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/usingProjectsTable.jspf b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/usingProjectsTable.jspf index 055175035a..9cc0052d5a 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/usingProjectsTable.jspf +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/utils/includes/usingProjectsTable.jspf @@ -15,7 +15,7 @@ (${usingProjects.size()} visible / ${allUsingProjectsCount - usingProjects.size()} restricted) projects.
    - +
    @@ -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 cdcdc67980..3e8edee6e9 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language.properties @@ -105,6 +105,7 @@ authorization.header.authorization.token.api.token=Authorization Header (Authori auto.refresh.in=Auto-refresh in auto-refresh.in.5=Auto-refresh in 5 ba-bl.slash.group=BA-BL/Group +based.on.license.file.count=based on license file count basic.fields=Basic fields basic.info=Basic Info bazaar=Bazaar @@ -241,6 +242,7 @@ commercial.details=Commercial Details commercial.details.administration=Commercial Details Administration committer=Committer common.weakness.enumeration=Common weakness enumeration +complexity=Complexity component=Component component.clearing.report=Component Clearing Report component.could.not.be.added=Component could not be added. @@ -539,6 +541,7 @@ error=Error error.adding.comment.to.clearing.request=Error adding comment to clearing request error.creating.clearing.request=Error creating clearing request! error.fetching.component.from.backend=Error fetching component from backend. +error.fetching.license.info.from.ISR.file=Error fetching license info from ISR file error.fetching.license.to.source.file.mapping=Error fetching license to source file mapping error.fetching.project.from.backend=Error fetching project from backend. error.fetching.release.from.backend=Error fetching release from backend. @@ -580,6 +583,7 @@ failed.to.delete.the.obligation=Failed to delete the obligation! failed.to.edit.secondary.departments.and.roles.for.user=Failed to edit Secondary Departments and Roles for user failed.to.fetch.clearing.request.from.db=Failed to fetch clearing request from database! failed.to.load=Failed to load! +failed.to.load.scanner.findings.with.error=Failed to load Scanner findings with error failed.to.load.source.file.with.error=Failed to load source file with error failed.to.reopen.clearing.request=Failed to reopen clearing request! failed.to.update.clearing.request=Failed to update clearing request! @@ -664,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 @@ -692,10 +696,12 @@ is.a.subproject=Is a subproject is.checked=Is checked is.used.by.a.total.of.allUsingProjectsCount.usingProjects.size.visible.allUsingProjectsCount.usingProjects.size.restricted.projects=is used by a total of ${allUsingProjectsCount} (${usingProjects.size()} visible / ${allUsingProjectsCount - usingProjects.size()} restricted) projects. is.used.by.the.following.components=is used by the following components +isr.attachment.not.found.in.the.release=ISR (Initial Scan Reports) attachment not found in release keep.password.empty.to.reuse.old.password=Keep password empty to reuse old password key.user=Key user keyword.search=Keyword Search languages=Languages +large=Large last.7.days=Last 7 days last.30.days=Last 30 days last.export.happened.with.old.storage.format.so.restored.data.might.not.be.correct.for.attachments.of.releases.in.subprojects=Last export happened with old storage format, so restored data might not be correct for attachments of releases in subprojects. @@ -729,6 +735,7 @@ license.details=License Details license.fullname=License Fullname license.info=License Info license.info.header=License Info Header +license.information.not.found.in.isr=License information not found in ISR (Initial Scan Report) license.names=License names licenses=Licenses license.clearing=License Clearing @@ -809,6 +816,7 @@ more.info=More Info more.than.1000.documents.affected.the.merge.operation.might.time.out.in.consequence.only.some.of=More than 1000 documents affected. The merge operation might time out. In consequence only some of multiple.approved.cli.are.found.in.the.release=Multiple approved CLI are found in release multiple.attachments.with.same.name.or.content.cannot.be.present.in.attachment.list=Multiple attachments with same name or content cannot be present in attachment list. +multiple.isr.are.found.in.the.release=Multiple ISR (Initial Scan Reports) are found in release my.components=My Components my.projects=My Projects my.subscriptions=My Subscriptions @@ -978,6 +986,7 @@ please.select.the.project.visibility=Please select the project visibility! please.select.the.component.visibility=Please select the component visibility! please.select.the.server=Please select the server! prease.enter.a.valid.url=Please enter a valid URL! +possible.main.license.ids=Possible Main License Ids postpone.request=Postpone Request pre.evaluation.date.yyyy.mm.dd=Pre-evaluation date YYYY-MM-DD preferred.clearing.date=Preferred Clearing Date @@ -1201,6 +1210,7 @@ show.x.entries=Show _MENU_ entries side.by.side=Side by side sign.in=Sign In size=Size +small=Small software.platforms=Software Platforms some.of.the.stored.selection.could.not.be.restored.please.check.carefully=Some of the stored selection could not be restored. Please check carefully! some.projects.failed.to.import=Some projects failed to import @@ -1216,6 +1226,7 @@ source.code.self.made=Source Code Self-Made source.code.tool.made=Source Code Tool-Made source.component=Source component source.file.information.not.found.in.cli=Source file information not found in CLI +source.file.information.not.found.in.isr=Source file information not found in ISR source.release=Source release: source.vendor=Source vendor spdx.attachments=SPDX Attachments @@ -1271,6 +1282,7 @@ the.license.type.x.cannot.be.deleted.since.it.is.being.used.in.some.licenses.ple the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.release=the documents might be changed accordingly. In this case just restart the operation as long as the source release the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.vendor=the documents might be changed accordingly. In this case just restart the operation as long as the source vendor the.fields.assessor.department.and.assessement.date.will.be.taken.as.well="The fields Assessor Department and Assessement Date will be taken as well." +the.final.license.list.may.differ.based.on.the.conclusions.made.by.the.clearing.expert.and.is.made.available.as.component.license.information.cli=The final license lists may differ based on the conclusions made by the clearing expert and is made available as Component License Information (CLI). the.following.documents.will.be.affected.by.this.merge.and.are.changed.accordingly=The following documents will be affected by this merge and are changed accordingly: the.following.duplicate.identifiers.were.found=The following duplicate identifiers were found. the.following.projects.will.be.imported=The following projects will be imported: @@ -1292,6 +1304,7 @@ this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.adminis this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.administrator.with.the.following.information=This error can lead to inconsistencies in the database. Please inform the administrator with the following information: this.function.is.meant.to.be.followed.by.a.new.license.import=This function is meant to be followed by a new license import. this.is.auto.generated.comment=*** This is auto-generated comment ***
    +this.is.only.an.initial.scanner.isr.finding.of.the.contained.licenses.in.the.uploaded.source.file=This is only an Initial Scanner (ISR) finding of the contained licenses in the uploaded source file. this.license.is.unchecked=This license is UNCHECKED. this.obligation.is.not.associated.with.linked.release=This obligation is not associated with linked release this.project.contains=This project contains @@ -1301,7 +1314,9 @@ this.release.x.contains.1=This release contains title=Title to=To to.be.replaced=To be replaced +to.view.the.files.corresponding.to.each.licenses.go.to.clearing.details.tab.of.respective.release=To view the files corresponding to each licenses, go to "Clearing Details" tab of respective Release. today=Today +total.number.of.files=Total number of files enable.svm=Enable SVM obligation=Obligation obligation.details=Obligation Details @@ -1384,12 +1399,14 @@ VerificationState-CHECKED=It is verified. VerificationState-INCORRECT=It was decided that the verification should be rejected. VerificationState-NOT_CHECKED=No one has yet looked at this and verified it. version=Version +very.large=Very Large view.clearing.request=View Clearing Request view.clearing.request.failure.message=We are not able to find the clearing request [ID: ] in db for the project
    Try again later. view.by.releases=View by Releases view.change.logs=View Change Logs view.file.list=View file list view.obligations=View Obligations +view.scanner.findings.license=View scanner findings (License) visibility=Visibility Visibility=Private: Only visible by creator (and admin which applies to all visibility levels) Me and Moderators: Visible by creator and moderators Group and Moderators: All users of the same group and the moderators Everyone: Every user who is logged into the system Visibility-BUISNESSUNIT_AND_MODERATORS=All users of the same group and the moderators. @@ -1496,6 +1513,30 @@ 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 + ## Refer to http://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/ and add your datatables language datatables.lang=https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/English.json 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 5788a72cdc..94920263db 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language_ja.properties @@ -105,6 +105,7 @@ authorization.header.authorization.token.api.token=認証ヘッダ, (認証 API- auto.refresh.in=自動更新 auto-refresh.in.5=5分毎に自動更新 ba-bl.slash.group=BA-BL/Group +based.on.license.file.count=based on license file count basic.fields=基本分野 basic.info=基本情報 bazaar=Bazaar @@ -241,6 +242,7 @@ commercial.details=商用物の詳細情報 commercial.details.administration=商用物の詳細情報管理 committer=コミッター common.weakness.enumeration=CWE(common.weakness.enumeration) +complexity=Complexity component=コンポーネント component.clearing.report=コンポーネントクリアリングレポート component.could.not.be.added=コンポーネントを追加できませんでした。 @@ -539,6 +541,7 @@ error=エラー error.adding.comment.to.clearing.request=クリアリングリクエスト コメント追加エラー error.creating.clearing.request=クリアリングリクエストコメント追加エラー! error.fetching.component.from.backend=バックエンドからのコンポーネントの取得する際にエラーが発生 +error.fetching.license.info.from.ISR.file=Error fetching license info from ISR file error.fetching.license.to.source.file.mapping=Error fetching license to source file mapping error.fetching.project.from.backend=バックエンドからプロジェクトを取得する際にエラーが発生 error.fetching.release.from.backend=バックエンドからリリースを取得する際にエラーが発生 @@ -580,6 +583,7 @@ failed.to.delete.the.obligation=オブリゲーション削除失敗! failed.to.edit.secondary.departments.and.roles.for.user=第2所属部門とロールの編集失敗! failed.to.fetch.clearing.request.from.db=データベースからクリアリングリクエスト取得失敗! failed.to.load=ロード失敗! +failed.to.load.scanner.findings.with.error=Failed to load Scanner findings with error failed.to.load.source.file.with.error=エラーによりソースファイルのロードに失敗しました. failed.to.reopen.clearing.request=クリアリングリクエストを再び開くのに失敗しました! failed.to.update.clearing.request=クリアリングリクエストを更新するのに失敗しました! @@ -664,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=間違い @@ -692,10 +696,12 @@ is.a.subproject=サブプロジェクトは is.checked=チェック済 is.used.by.a.total.of.allUsingProjectsCount.usingProjects.size.visible.allUsingProjectsCount.usingProjects.size.restricted.projects=は、${allUsingProjectsCount} (${usingProjects.size()}見えるプロジェクト / ${allUsingProjectsCount - usingProjects.size()}制限されたプロジェクトの合計${allUsingProjectsCount})で利用されています。 is.used.by.the.following.components=は以下のコンポーネントで使用されます。 +isr.attachment.not.found.in.the.release=ISR (Initial Scan Reports) attachment not found in release keep.password.empty.to.reuse.old.password=古いパスワードを再利用するためにはパスワードを空にしてください key.user=キーユーザ keyword.search=キーワード検索 languages=言語 +large=Large last.7.days=過去7日間 last.30.days=過去30日間 last.export.happened.with.old.storage.format.so.restored.data.might.not.be.correct.for.attachments.of.releases.in.subprojects=最後のエクスポートは古いストレージ形式で行われたため、サブプロジェクト内のリリースの添付ファイルでは復元されたデータが正しくない可能性があります。 @@ -729,6 +735,7 @@ license.details=ライセンスの詳細 license.fullname=ライセンスのフルネーム license.info=ライセンス情報 license.info.header=ライセンス情報ヘッダ +license.information.not.found.in.isr=License information not found in ISR (Initial Scan Report) license.names=ライセンス名 licenses=ライセンス license.clearing=ライセンスクリアリング @@ -809,6 +816,7 @@ more.info=詳細情報 more.than.1000.documents.affected.the.merge.operation.might.time.out.in.consequence.only.some.of=1000以上のドキュメントが影響を受けています。結果として、一部のマージ操作がタイムアウトする可能性があります。 multiple.approved.cli.are.found.in.the.release=承認された複数のCLIがリリースに見つかりました. multiple.attachments.with.same.name.or.content.cannot.be.present.in.attachment.list=同じ名前または内容の複数の添付ファイルが添付ファイル リストに存在することはできません。 +multiple.isr.are.found.in.the.release=Multiple ISR (Initial Scan Reports) are found in release my.components=マイコンポーネント my.projects=マイプロジェクト my.subscriptions=マイサブスクリプション @@ -978,6 +986,7 @@ please.select.the.project.visibility=プロジェクトの可視性を選択し please.select.the.component.visibility=コンポーネントの可視性を選択してください please.select.the.server=サーバーを選択してください prease.enter.a.valid.url=適切なURLを入力してください +possible.main.license.ids=Possible Main License Ids postpone.request=リクエスト延期 pre.evaluation.date.yyyy.mm.dd=事前評価日 YYYY-MM-DD preferred.clearing.date=理想的なクリアリング日時 @@ -1201,6 +1210,7 @@ show.x.entries=MENU_エントリを表示する side.by.side=横に並んで sign.in=サインイン size=サイズ +small=Small software.platforms=ソフトウェアプラットフォーム some.of.the.stored.selection.could.not.be.restored.please.check.carefully=保存されている選択範囲の一部が復元できませんでした。よく確認してください。 some.projects.failed.to.import=一部のプロジェクトでインポートに失敗しました @@ -1216,6 +1226,7 @@ source.code.self.made=独自・自作のソースコード source.code.tool.made=ツール生成のソースコード source.component=ソースコンポーネント source.file.information.not.found.in.cli=ソースファイル情報がCLIの中に見つからない +source.file.information.not.found.in.isr=Source file information not found in ISR source.release=ソースリリース。 source.vendor=ソースベンダ spdx.attachments=SPDXアタッチメント @@ -1271,6 +1282,7 @@ the.license.type.x.cannot.be.deleted.since.it.is.being.used.in.some.licenses.ple the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.release=を使用すると、ドキュメントが変更される可能性があります。この場合は、ソースリリースの the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.vendor=を使用すると、それに応じてドキュメントが変更される可能性があります。この場合は、ソースベンダーの the.fields.assessor.department.and.assessement.date.will.be.taken.as.well=Assessor DepartmentAssessement Date のフィールドも同様に取り込まれます。 +the.final.license.list.may.differ.based.on.the.conclusions.made.by.the.clearing.expert.and.is.made.available.as.component.license.information.cli=The final license lists may differ based on the conclusions made by the clearing expert and is made available as Component License Information (CLI). the.following.documents.will.be.affected.by.this.merge.and.are.changed.accordingly=以下の文書はこのマージの影響を受け、それに応じて変更されます。 the.following.duplicate.identifiers.were.found=以下の重複した識別子が見つかりました。 the.following.projects.will.be.imported=以下のプロジェクトがインポートされます。 @@ -1292,6 +1304,7 @@ this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.adminis this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.administrator.with.the.following.information=このエラーにより、データベースの不整合が発生する可能性があります。管理者に以下の情報をお知らせください。 this.function.is.meant.to.be.followed.by.a.new.license.import=この機能は、新しいライセンスのインポートに続くことを意図しています。 this.is.auto.generated.comment=*** This is auto-generated comment ***
    +this.is.only.an.initial.scanner.isr.finding.of.the.contained.licenses.in.the.uploaded.source.file=This is only an Initial Scanner (ISR) finding of the contained licenses in the uploaded source file. this.license.is.unchecked=このライセンスはUNCHECKEDです。 this.obligation.is.not.associated.with.linked.release=このオブリゲーションは、リンクされたリリースと無関係 this.project.contains=このプロジェクトには以下のものが含まれています。 @@ -1301,7 +1314,9 @@ this.release.x.contains.1=今回のリリース title=タイトル to=To to.be.replaced=置き換わる +to.view.the.files.corresponding.to.each.licenses.go.to.clearing.details.tab.of.respective.release=To view the files corresponding to each licenses, go to "Clearing Details" tab of respective Release. today=本日 +total.number.of.files=Total number of files enable.svm= SVM(Security Vulnerability Monitor)を有効 obligation=オブリゲーション obligation.details=オブリゲーション詳細 @@ -1384,12 +1399,14 @@ VerificationState-CHECKED=確認済みです。 VerificationState-INCORRECT=検証を拒否することが決定されました。 VerificationState-NOT_CHECKED=まだ誰もこれを見て検証していない。 version=バージョン +very.large=Very Large view.clearing.request=クリアリングリクエストビュー view.clearing.request.failure.message=クリアリングリクエストを発見できない [ID: ] プロジェクトのデータベース
    再試行してください. view.by.releases=リリースごとに表示 view.change.logs=変更ログビュー view.file.list=ファイルリストビュー view.obligations=オブリゲーションを表示 +view.scanner.findings.license=View scanner findings (License) visibility=可視範囲 Visibility=Private: 作成者(およびすべての表示レベルに適用される管理者)のみが表示できます。 Me and Moderators: 作成者とモデレーターが表示できます。 Group and Moderators: 同じグループメンバーとモデレータが見れる Everyone: このシステムにログインしている人全員が見れる Visibility-BUISNESSUNIT_AND_MODERATORS=同じグループのすべてのユーザーとモデレーター。 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 59fc89e74b..d972c71ab4 100644 --- a/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties +++ b/frontend/sw360-portlet/src/main/resources/content/Language_vi.properties @@ -106,6 +106,7 @@ authorization.header.authorization.token.api.token=Phần đầu mã truy cập. auto.refresh.in=Tự động làm mới trong auto-refresh.in.5=Tự động làm mới trong 5 ba-bl.slash.group=BA-BL/Group +based.on.license.file.count=based on license file count basic.fields=Các trường cơ bản bazaar=Chợ basic.info=Basic Info @@ -242,6 +243,7 @@ commercial.details=Chi tiết thương mại commercial.details.administration=Quản trị chi tiết thương mại committer=Cộng đồng common.weakness.enumeration=Bảng liệt kê điểm yếu chung +complexity=Complexity component=Thành phần component.clearing.report=Báo cáo dọn dẹp thành phần component.could.not.be.added=Thành phần không thể được thêm vào. @@ -543,6 +545,7 @@ error=lỗi error.adding.comment.to.clearing.request=Lỗi thêm bình luận để xóa yêu cầu error.creating.clearing.request=Error creating clearing request! error.fetching.component.from.backend=Lỗi tìm nạp thành phần từ Backend. +error.fetching.license.info.from.ISR.file=Error fetching license info from ISR file error.fetching.license.to.source.file.mapping=Error fetching license to source file mapping error.fetching.project.from.backend=Lỗi tìm nạp dự án từ Backend. error.fetching.release.from.backend=Lỗi tìm nạp bản phát hành từ Backend. @@ -584,6 +587,7 @@ failed.to.delete.the.obligation=Không thể xóa nghĩa vụ! failed.to.edit.secondary.departments.and.roles.for.user=Failed to edit Secondary Departments and Roles for user failed.to.fetch.clearing.request.from.db=Failed to fetch clearing request from database! failed.to.load=Failed to load! +failed.to.load.scanner.findings.with.error=Failed to load Scanner findings with error failed.to.load.source.file.with.error=Failed to load source file with error failed.to.reopen.clearing.request=Failed to reopen clearing request! failed.to.update.clearing.request=Failed to update clearing request! @@ -668,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 @@ -696,10 +700,12 @@ is.a.subproject=Là một tiểu dự án is.checked=Đã được kiểm tra is.used.by.a.total.of.allUsingProjectsCount.usingProjects.size.visible.allUsingProjectsCount.usingProjects.size.restricted.projects=được sử dụng bởi tổng số các dự án ${allUsingProjectsCount} (${usingProjects.size()} nhìn thấy / ${allUsingProjectsCount - usedProjects.size()}). is.used.by.the.following.components=được sử dụng bởi các thành phần sau +isr.attachment.not.found.in.the.release=ISR (Initial Scan Reports) attachment not found in release keep.password.empty.to.reuse.old.password=Keep password empty to reuse old password key.user=Người dùng chính keyword.search=Tìm kiếm từ khóa languages=Ngôn ngữ +large=Large last.7.days=Last 7 days last.30.days=Last 30 days last.export.happened.with.old.storage.format.so.restored.data.might.not.be.correct.for.attachments.of.releases.in.subprojects=Lần xuất cuối cùng xảy ra với định dạng lưu trữ cũ, do đó dữ liệu được khôi phục có thể không chính xác đối với tệp đính kèm của bản phát hành trong các dự án con. @@ -733,6 +739,7 @@ license.details=Chi tiết giấy phép license.fullname=Tên đầy đủ của giấy phép license.info=Thông tin giấy phép license.info.header=Tiêu đề thông tin giấy phép +license.information.not.found.in.isr=License information not found in ISR (Initial Scan Report) license.names=Tên giấy phép licenses=Giấy phép license.clearing=License Clearing @@ -813,6 +820,7 @@ more.info=Thêm thông tin more.than.1000.documents.affected.the.merge.operation.might.time.out.in.consequence.only.some.of=Hơn 1000 tài liệu bị ảnh hưởng. Hoạt động hợp nhất có thể hết thời gian. Do đó, chỉ có một số multiple.approved.cli.are.found.in.the.release=Multiple approved CLI are found in release multiple.attachments.with.same.name.or.content.cannot.be.present.in.attachment.list=Nhiều tệp đính kèm có cùng tên hoặc nội dung không thể có trong danh sách tệp đính kèm. +multiple.isr.are.found.in.the.release=Multiple ISR (Initial Scan Reports) are found in release my.components=Thành phần của tôi my.projects=Dự án của tôi my.subscriptions=Đăng ký của tôi @@ -977,6 +985,7 @@ please.select.the.project.visibility=Vui lòng chọn tầm nhìn của dự án please.select.the.component.visibility=Please select the component visibility! please.select.the.server=Vui lòng chọn máy chủ! prease.enter.a.valid.url=Please enter a valid URL! +possible.main.license.ids=Possible Main License Ids postpone.request=Yêu cầu trì hoãn pre.evaluation.date.yyyy.mm.dd=Ngày đánh giá trước YYYY-MM-DD preferred.clearing.date=Preferred Clearing Date @@ -1198,6 +1207,7 @@ show.x.entries=Hiện thị _MENU_ mục side.by.side=Bên cạnh nhau sign.in=Đăng nhập size=Kích thước +small=Small software.platforms=Nền tảng phần mềm some.of.the.stored.selection.could.not.be.restored.please.check.carefully=Một số lựa chọn được lưu trữ không thể được khôi phục. Vui lòng kiểm tra cẩn thận! some.projects.failed.to.import=Một số dự án không thể nhập @@ -1213,6 +1223,7 @@ source.code.self.made=Mã nguồn tự làm source.code.tool.made=Mã nguồn được tạo ra source.component=Thành phần nguồn source.file.information.not.found.in.cli=Source file information not found in CLI +source.file.information.not.found.in.isr=Source file information not found in ISR source.release=Phát hành nguồn: source.vendor=Nhà cung cấp nguồn spdx.attachments=Tệp đính kèm SPDX @@ -1268,6 +1279,7 @@ the.license.type.x.cannot.be.deleted.since.it.is.being.used.in.some.licenses.ple the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.release=các tài liệu có thể được thay đổi cho phù hợp. Trong trường hợp này, chỉ cần khởi động lại hoạt động miễn là phát hành nguồn the.documents.might.be.changed.accordingly.in.this.case.just.restart.the.operation.as.long.as.the.source.vendor=các tài liệu có thể được thay đổi cho phù hợp. Trong trường hợp này, chỉ cần khởi động lại hoạt động miễn là nhà cung cấp nguồn the.fields.assessor.department.and.assessement.date.will.be.taken.as.well="Những trường Người giám địnhNgày đánh giá cũng sẽ được thực hiện." +the.final.license.list.may.differ.based.on.the.conclusions.made.by.the.clearing.expert.and.is.made.available.as.component.license.information.cli=The final license lists may differ based on the conclusions made by the clearing expert and is made available as Component License Information (CLI). the.following.documents.will.be.affected.by.this.merge.and.are.changed.accordingly=Các tài liệu sau đây sẽ bị ảnh hưởng bởi sự hợp nhất này và được thay đổi tương ứng: the.following.duplicate.identifiers.were.found=Các định danh trùng lặp sau đây đã được tìm thấy. the.following.projects.will.be.imported=Các dự án sau đây sẽ được nhập: @@ -1289,6 +1301,7 @@ this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.adminis this.error.can.lead.to.inconsistencies.in.the.database.please.inform.the.administrator.with.the.following.information=Lỗi này có thể dẫn đến sự không nhất quán trong cơ sở dữ liệu. Vui lòng thông báo cho quản trị viên với các thông tin sau: this.function.is.meant.to.be.followed.by.a.new.license.import=Chức năng này có nghĩa là được theo sau bởi nhập một giấy phép mới. this.is.auto.generated.comment=*** This is auto-generated comment ***
    +this.is.only.an.initial.scanner.isr.finding.of.the.contained.licenses.in.the.uploaded.source.file=This is only an Initial Scanner (ISR) finding of the contained licenses in the uploaded source file. this.license.is.unchecked=Giấy phép này là CHƯA KIỂM TRA. this.obligation.is.not.associated.with.linked.release=Nghĩa vụ này không liên quan đến phát hành liên kết this.project.contains=Dự án này chứa @@ -1298,7 +1311,9 @@ this.release.x.contains.1=Bản phát hành chứ title=Tiêu đề to=To to.be.replaced=Sẽ được thay thế +to.view.the.files.corresponding.to.each.licenses.go.to.clearing.details.tab.of.respective.release=To view the files corresponding to each licenses, go to "Clearing Details" tab of respective Release. today=Today +total.number.of.files=Total number of files #oblig=Việc cần làm obligation=Obligation #oblig.details=Chi tiết việc cần làm @@ -1388,12 +1403,14 @@ VerificationState-CHECKED=Nó được xác minh. VerificationState-INCORRECT=Nó đã được quyết định rằng việc xác minh nên bị từ chối. VerificationState-NOT_CHECKED=Không ai đã xem xét điều này và xác minh nó. version=Phiên bản +very.large=Very Large view.clearing.request=View Clearing Request view.clearing.request.failure.message=We are not able to find the clearing request [ID: ] in db for the project
    Try again later. view.by.releases=Xem bởi các bản phát hành view.change.logs=View Change Logs view.file.list=View file list view.obligations=Xem nghĩa vụ +view.scanner.findings.license=View scanner findings (License) visibility=Tầm nhìn Visibility=Riêng tư: Chỉ hiển thị bởi người tạo (và quản trị viên áp dụng cho tất cả các mức độ hiển thị) Tôi và Người kiểm duyệt: Hiển thị bởi người tạo và người kiểm duyệt Nhóm và Người kiểm duyệt: Tất cả người dùng của cùng một nhóm và người kiểm duyệt Mọi người: Mọi người dùng đăng nhập vào hệ thống Visibility-BUISNESSUNIT_AND_MODERATORS=Tất cả người dùng của cùng một nhóm và người điều hành. @@ -1501,6 +1518,11 @@ object=Đối tượng 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. +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 + ## Refer to http://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/ and add your datatables language datatables.lang=https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Vietnamese.json 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 6b066e3687..6c238e8209 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 @@ -38,6 +38,9 @@ import org.eclipse.sw360.datahandler.thrift.users.UserService; 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; import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -303,6 +306,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 4f6ccd7a31..fdc8191ccd 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -235,4 +245,125 @@ public static abstract class ProjectReleaseRelationshipMixin extends ProjectRele }) public static abstract class ProjectProjectRelationshipMixin extends ProjectProjectRelationship { } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonIgnoreProperties({ + "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 { + } + } 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..8c60f2d488 --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/couchdb/DatabaseMixInForSPDXDocument.java @@ -0,0 +1,226 @@ +/* + * 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; + +/* + * @author nam1.nguyenphuong@toshiba.co.jp + */ +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 1e921bec1b..1d952ce153 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. @@ -153,6 +156,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..87becbd209 --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentCreationInfoPermissions.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * Created on 11/08/2021. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..08bf5452e6 --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxDocumentPermissions.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * Created on 10/08/2021. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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..e1151bee64 --- /dev/null +++ b/libraries/lib-datahandler/src/main/java/org/eclipse/sw360/datahandler/permissions/SpdxPackageInfoPermissions.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * Created on 11/08/2021. + * + * @author hieu1.phamvan@toshiba.co.jp + */ +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 6f2defeae3..b4367010c4 100644 --- a/libraries/lib-datahandler/src/main/thrift/changelogs.thrift +++ b/libraries/lib-datahandler/src/main/thrift/changelogs.thrift @@ -30,7 +30,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 519f83768c..8dcc3058e2 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, } enum ComponentType { @@ -824,10 +827,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. @@ -838,4 +846,9 @@ service ComponentService { * Gets all releases with complete details */ 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); } 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 3ce14ce4f8..168a7a5054 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();