From 49f9f8e9e7ceb463bb635da285d501e7e7f01713 Mon Sep 17 00:00:00 2001 From: Nikolas Sepos Date: Tue, 28 May 2019 16:18:42 +0300 Subject: [PATCH] fix(report): corrections to report As per: https://github.com/siemens/sw360/issues/18 Signed-off-by: Nikolas Sepos --- .../sw360/licenseinfo/LicenseInfoHandler.java | 2 +- .../outputGenerators/DocxGenerator.java | 101 ++++++++++++------ .../src/main/resources/templateReport.docx | Bin 11581 -> 12587 bytes .../portlets/projects/ProjectPortlet.java | 5 +- .../webapp/html/components/editRelease.jsp | 2 + .../releases/editReleaseInformation.jspf | 28 +++-- .../src/main/thrift/components.thrift | 1 + .../project/ProjectController.java | 8 +- 8 files changed, 98 insertions(+), 49 deletions(-) diff --git a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/LicenseInfoHandler.java b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/LicenseInfoHandler.java index 73abed993f..72b29611a4 100644 --- a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/LicenseInfoHandler.java +++ b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/LicenseInfoHandler.java @@ -94,7 +94,7 @@ protected LicenseInfoHandler(AttachmentDatabaseHandler attachmentDatabaseHandler new TextGenerator(DISCLOSURE, "License Disclosure as TEXT"), new XhtmlGenerator(DISCLOSURE, "License Disclosure as XHTML"), new DocxGenerator(DISCLOSURE, "License Disclosure as DOCX"), - new DocxGenerator(REPORT, "License Report as DOCX") + new DocxGenerator(REPORT, "Project Clearing Report as DOCX") ); // @formatter:on } diff --git a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/outputGenerators/DocxGenerator.java b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/outputGenerators/DocxGenerator.java index 63dd39e41c..8bd5aebf42 100644 --- a/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/outputGenerators/DocxGenerator.java +++ b/backend/src/src-licenseinfo/src/main/java/org/eclipse/sw360/licenseinfo/outputGenerators/DocxGenerator.java @@ -15,6 +15,7 @@ import org.apache.log4j.Logger; import org.apache.poi.xwpf.usermodel.*; import org.apache.thrift.TException; +import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; import org.eclipse.sw360.datahandler.common.CommonUtils; import org.eclipse.sw360.datahandler.common.SW360Utils; @@ -29,6 +30,8 @@ import org.eclipse.sw360.datahandler.thrift.licenses.LicenseService; import org.eclipse.sw360.datahandler.thrift.licenses.Todo; 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.users.User; import org.eclipse.sw360.datahandler.thrift.users.UserService; @@ -47,17 +50,24 @@ public class DocxGenerator extends OutputGenerator { private static final Logger LOGGER = Logger.getLogger(DocxGenerator.class); private static final String UNKNOWN_LICENSE_NAME = "Unknown license name"; private static final String UNKNOWN_FILE_NAME = "Unknown file name"; + private static final String UNKNOWN_LICENSE = "Unknown"; private static final String TODO_DEFAULT_TEXT = "todo not determined so far."; private static final String DOCX_TEMPLATE_FILE = "/templateFrontpageContent.docx"; private static final String DOCX_TEMPLATE_REPORT_FILE = "/templateReport.docx"; private static final String DOCX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; private static final String DOCX_OUTPUT_TYPE = "docx"; - public static final String UNKNOWN_LICENSE = "Unknown"; + private static final long ADDITIONAL_REQ_THRESHOLD = 3; - public static final int ADDITIONAL_REQ_TABLE_INDEX = 5; + + public static final int OVERVIEW_TABLE_INDEX = 0; + public static final int SPECIAL_OSS_RISKS_TABLE_INDEX = 1; public static final int DEV_DETAIL_TABLE_INDEX = 2; + public static final int THIRD_PARTY_COMPONENT_OVERVIEW_TABLE_INDEX = 3; private static final int COMMON_RULES_TABLE_INDEX = 4; + public static final int ADDITIONAL_REQ_TABLE_INDEX = 5; + + public DocxGenerator(OutputFormatVariant outputFormatVariant, String description) { super(DOCX_OUTPUT_TYPE, description, true, DOCX_MIME_TYPE, outputFormatVariant); @@ -136,7 +146,7 @@ private void fillDisclosureDocument( fillReleaseBulletList(document, projectLicenseInfoResults); fillReleaseDetailList(document, projectLicenseInfoResults, includeObligations); fillLicenseList(document, projectLicenseInfoResults); - } + } private void fillReportDocument( XWPFDocument document, @@ -147,6 +157,7 @@ private void fillReportDocument( Collection obligationResults, User user) throws XmlException, TException { + String businessUnit = project.getBusinessUnit(); String projectName = project.getName(); String projectVersion = project.getVersion(); String obligationsText = project.getObligationsText(); @@ -157,11 +168,13 @@ private void fillReportDocument( String deliveryChannelsText = project.getDeliveryChannels(); String remarksAdditionalRequirementsText = project.getRemarksAdditionalRequirements(); String projectDescription = project.getDescription(); - + // extract licenses that appear at least ADDITIONAL_REQ_THRESHOLD times + Set mostLicenses = extractMostCommonLicenses(obligationResults, ADDITIONAL_REQ_THRESHOLD); fillOwnerGroup(document, project); fillAttendeesTable(document, project); + replaceText(document, "$bunit", businessUnit); replaceText(document, "$license-info-header", licenseInfoHeaderText); replaceText(document, "$project-name", projectName); replaceText(document, "$project-version", projectVersion); @@ -175,13 +188,13 @@ private void fillReportDocument( replaceText(document, "$product-description", projectDescription); fillSpecialOSSRisksTable(document, project, obligationResults); - fillDevelopmentDetailsTable(document, project, user); + fillDevelopmentDetailsTable(document, project, user, projectLicenseInfoResults); fillOverview3rdPartyComponentTable(document, projectLicenseInfoResults); + fillCommonRulesTable(document, project); - fillAdditionalRequirementsTable(document, obligationResults); + replaceText(document, "$list_comma_sep_licenses_above_threshold", String.join(", ", mostLicenses)); + fillAdditionalRequirementsTable(document, obligationResults, mostLicenses); - // because of the impossible API component subsections must be the last thing in the docx file - // the rest of the sections must be generated after this writeComponentSubsections(document, projectLicenseInfoResults, obligationResults); } @@ -194,9 +207,9 @@ private void fillOwnerGroup(XWPFDocument document, Project project) throws XmlEx } private void fillAttendeesTable(XWPFDocument document, Project project) throws XmlException, TException { - XWPFTable table = document.getTables().get(0); + XWPFTable table = document.getTables().get(OVERVIEW_TABLE_INDEX); - int currentRow = 6; + int currentRow = 7; UserService.Iface userClient = new ThriftClients().makeUserClient(); @@ -220,7 +233,12 @@ private void fillAttendeesTable(XWPFDocument document, Project project) throws X continue; } - User user = userClient.getByEmail(email); + User user = null; + try { + user = userClient.getByEmail(email); + } catch (TException te) { + // a resulting null user object is handled below by replacing with email + } XWPFTableRow row = table.insertNewTableRow(currentRow++); String name = email; @@ -229,7 +247,7 @@ private void fillAttendeesTable(XWPFDocument document, Project project) throws X } String department = "N.A."; if(user != null) { - name = user.getDepartment(); + department = user.getDepartment(); } row.addNewTableCell().setText(name); @@ -241,7 +259,7 @@ private void fillAttendeesTable(XWPFDocument document, Project project) throws X } private void fillSpecialOSSRisksTable(XWPFDocument document, Project project, Collection obligationResults) throws XmlException, TException { - XWPFTable table = document.getTables().get(1); + XWPFTable table = document.getTables().get(SPECIAL_OSS_RISKS_TABLE_INDEX); final int[] currentRow = new int[]{0}; obligationResults.stream() @@ -260,7 +278,7 @@ private void fillSpecialOSSRisksTable(XWPFDocument document, Project project, Co } private void fillOverview3rdPartyComponentTable(XWPFDocument document, Collection projectLicenseInfoResults) throws XmlException { - XWPFTable table = document.getTables().get(3); + XWPFTable table = document.getTables().get(THIRD_PARTY_COMPONENT_OVERVIEW_TABLE_INDEX); int currentRow = 1; for(LicenseInfoParsingResult result : projectLicenseInfoResults) { @@ -292,17 +310,31 @@ private static Optional obligationsForRelease(Release r return obligationResults.stream().filter(opr -> opr.getRelease() == release).findFirst(); } - private void writeComponentSubsections(XWPFDocument document, Collection projectLicenseInfoResults, Collection obligationResults) throws XmlException { + private void writeComponentSubsections(XWPFDocument document, Collection projectLicenseInfoResults, Collection obligationResults) throws SW360Exception, XmlException { + XmlCursor cursor = document.getTables().get(ADDITIONAL_REQ_TABLE_INDEX).getCTTbl().newCursor(); + cursor.toEndToken(); for (LicenseInfoParsingResult result : projectLicenseInfoResults) { + while (cursor.currentTokenType() != XmlCursor.TokenType.START && cursor.hasNextToken()) { + cursor.toNextToken(); + } - XWPFParagraph title = document.createParagraph(); + if (cursor.currentTokenType() != XmlCursor.TokenType.START) { + throw new SW360Exception("Corrupt template; unable find start token"); + } + + XWPFParagraph title = document.insertNewParagraph(cursor); title.setStyle(STYLE_HEADING_3); title.setNumID(new BigInteger("2")); XWPFRun titleRun = title.createRun(); titleRun.setText(result.getVendor() + " " + result.getName()); - XWPFParagraph description = document.createParagraph(); + if (cursor.hasNextToken()) { + cursor.toNextToken(); + } else { + throw new SW360Exception("Corrupt template; unable to proceed to next token"); + } + XWPFParagraph description = document.insertNewParagraph(cursor); XWPFRun descriptionRun = description.createRun(); LicenseInfo licenseInfo = result.getLicenseInfo(); @@ -331,7 +363,7 @@ private void writeComponentSubsections(XWPFDocument document, Collection obligations = obligationsResult.getObligations(); - XWPFTable table = document.createTable(); + XWPFTable table = document.insertNewTbl(cursor); for (Obligation o : obligations) { XWPFTableRow row = table.insertNewTableRow(currentRow++); String licensesString = String.join(" ", o.getLicenseIDs()); @@ -343,29 +375,34 @@ private void writeComponentSubsections(XWPFDocument document, Collection projectLicenseInfoResults) throws TException { XWPFTable table = document.getTables().get(DEV_DETAIL_TABLE_INDEX); int currentRow = 1; - ComponentService.Iface compClient = new ThriftClients().makeComponentClient(); - List rll = compClient.getLinkedReleases(project.getReleaseIdToUsage()); + for(LicenseInfoParsingResult result : projectLicenseInfoResults) { + if (result.getStatus() != LicenseInfoRequestStatus.SUCCESS) { + // this error handling is for extra safety since projectLicenseInfoResults is provided by the caller + // and we assume valid input so we silently ignoring it. + continue; + } - for (ReleaseLink rl : rll) { - Release r = compClient.getReleaseById(rl.getId(), user); - Component component = compClient.getComponentById(r.getComponentId(), user); + Release r = result.getRelease(); + if (r == null) { + continue; + } XWPFTableRow row = table.insertNewTableRow(currentRow++); - row.addNewTableCell().setText(component.getName()); + row.addNewTableCell().setText(r.getName()); - String operatingSystems = component.getOperatingSystemsSize() == 0 ? "Unknown operating systems" : String.join(" ", component.getOperatingSystems()); + String operatingSystems = r.getOperatingSystemsSize() == 0 ? "N/A" : String.join(" ", r.getOperatingSystems()); row.addNewTableCell().setText(operatingSystems); - String langs = component.getLanguagesSize() == 0 ? "Unknown languages" : String.join(" ", component.getLanguages()); + String langs = r.getLanguagesSize() == 0 ? "N/A" : String.join(" ", r.getLanguages()); row.addNewTableCell().setText(langs); - String platforms = component.getSoftwarePlatformsSize() == 0 ? "Unknown platforms" : String.join(" ", component.getSoftwarePlatforms()); + String platforms = r.getSoftwarePlatformsSize() == 0 ? "N/A" : String.join(" ", r.getSoftwarePlatforms()); row.addNewTableCell().setText(platforms); } } @@ -379,13 +416,11 @@ protected static Set extractMostCommonLicenses(Collection entry.getValue().longValue() >= threshold) .map(entry -> entry.getKey()) + .map(license -> license.replace("\n", "").replace("\r", "")) .collect(Collectors.toSet()); } - private void fillAdditionalRequirementsTable(XWPFDocument document, Collection obligationResults) throws XmlException { - // extract licenses that appear at least ADDITIONAL_REQ_THRESHOLD times - Set mostLicenses = extractMostCommonLicenses(obligationResults, ADDITIONAL_REQ_THRESHOLD); - + private void fillAdditionalRequirementsTable(XWPFDocument document, Collection obligationResults, Set mostLicenses) throws XmlException { XWPFTable table = document.getTables().get(ADDITIONAL_REQ_TABLE_INDEX); final int[] currentRow = new int[]{0}; @@ -393,7 +428,7 @@ private void fillAdditionalRequirementsTable(XWPFDocument document, Collection opr.getStatus() == ObligationInfoRequestStatus.SUCCESS) .flatMap(opr -> opr.getObligations().stream()) .filter(o -> o.getLicenseIDs().stream() - .anyMatch(lid -> mostLicenses.parallelStream().anyMatch(mlid -> mlid.equals(lid)))) + .anyMatch(lid -> mostLicenses.parallelStream().anyMatch(mlid -> mlid.equals(lid.replace("\n", "").replace("\r", ""))))) .forEach(o -> { currentRow[0] = currentRow[0] + 1; XWPFTableRow row = table.insertNewTableRow(currentRow[0]); diff --git a/backend/src/src-licenseinfo/src/main/resources/templateReport.docx b/backend/src/src-licenseinfo/src/main/resources/templateReport.docx index d81e0ef1ae2874d207502a3ddff85d37b0f34f35..cd3b1438faef3faf46b1af44a543380de2595fc5 100644 GIT binary patch delta 10494 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 D4Zgkc delta 9474 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 + @@ -179,6 +180,7 @@ Liferay.on('allPortletsReady', function() { autocomplete.prepareForMultipleHits('programminglanguages', ${programmingLanguages}); autocomplete.prepareForMultipleHits('op_systems', ${operatingSystemsAutoC}); + autocomplete.prepareForMultipleHits('platformsTB', ${platformsAutoC}); sw360Validate.validateWithInvalidHandlerNoIgnore('#releaseEditForm'); diff --git a/frontend/sw360-portlet/src/main/webapp/html/components/includes/releases/editReleaseInformation.jspf b/frontend/sw360-portlet/src/main/webapp/html/components/includes/releases/editReleaseInformation.jspf index 8efa9c9e8c..08923a484b 100644 --- a/frontend/sw360-portlet/src/main/webapp/html/components/includes/releases/editReleaseInformation.jspf +++ b/frontend/sw360-portlet/src/main/webapp/html/components/includes/releases/editReleaseInformation.jspf @@ -16,7 +16,7 @@ - + @@ -52,6 +52,17 @@ placeholder="e.g.,Linux,MAC,Windows,..." value=""/> + + + + + - - - - - - + + +
Release SummaryRelease Summary
+ + "/> +
"/> - -
+ +