From 3c674cb1cd4de437f0e78a1a23a0b64583243416 Mon Sep 17 00:00:00 2001 From: Markus Herpich Date: Sun, 7 Apr 2019 20:00:45 +0200 Subject: [PATCH] Corrections to the license report As per: https://github.com/siemens/sw360/issues/18 Signed-off-by: Nikolas Sepos --- .../sw360/licenseinfo/LicenseInfoHandler.java | 2 +- .../outputGenerators/DocxGenerator.java | 77 ++++++++++++------ .../src/main/resources/templateReport.docx | Bin 11329 -> 12396 bytes .../portlets/projects/ProjectPortlet.java | 5 +- .../webapp/html/components/editRelease.jsp | 2 + .../releases/editReleaseInformation.jspf | 15 +++- .../src/main/thrift/components.thrift | 1 + .../project/ProjectController.java | 8 +- 8 files changed, 75 insertions(+), 35 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 3d362bb7f2..3029711ce1 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.thrift.SW360Exception; @@ -46,16 +47,23 @@ 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 = 4; + + 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; + public static final int ADDITIONAL_REQ_TABLE_INDEX = 4; + + public DocxGenerator(OutputFormatVariant outputFormatVariant, String description) { super(DOCX_OUTPUT_TYPE, description, true, DOCX_MIME_TYPE, outputFormatVariant); @@ -134,7 +142,7 @@ private void fillDisclosureDocument( fillReleaseBulletList(document, projectLicenseInfoResults); fillReleaseDetailList(document, projectLicenseInfoResults, includeObligations); fillLicenseList(document, projectLicenseInfoResults); - } + } private void fillReportDocument( XWPFDocument document, @@ -145,6 +153,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(); @@ -155,11 +164,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,10 +186,9 @@ private void fillReportDocument( fillSpecialOSSRisksTable(document, project, obligationResults); fillDevelopmentDetailsTable(document, project, user); fillOverview3rdPartyComponentTable(document, projectLicenseInfoResults); - 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); } @@ -191,9 +201,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(); @@ -217,7 +227,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) { + + } XWPFTableRow row = table.insertNewTableRow(currentRow++); String name = email; @@ -226,7 +241,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); @@ -238,7 +253,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() @@ -257,7 +272,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) { @@ -289,17 +304,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(); + } + + if (cursor.currentTokenType() != XmlCursor.TokenType.START) { + throw new SW360Exception("Corrupt template; unable find start token"); + } - XWPFParagraph title = document.createParagraph(); + 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(); @@ -328,7 +357,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()); @@ -356,13 +385,13 @@ private void fillDevelopmentDetailsTable(XWPFDocument document, Project project, row.addNewTableCell().setText(component.getName()); - String operatingSystems = component.getOperatingSystemsSize() == 0 ? "Unknown operating systems" : String.join(" ", component.getOperatingSystems()); + String operatingSystems = component.getOperatingSystemsSize() == 0 ? "N/A" : String.join(" ", component.getOperatingSystems()); row.addNewTableCell().setText(operatingSystems); - String langs = component.getLanguagesSize() == 0 ? "Unknown languages" : String.join(" ", component.getLanguages()); + String langs = component.getLanguagesSize() == 0 ? "N/A" : String.join(" ", component.getLanguages()); row.addNewTableCell().setText(langs); - String platforms = component.getSoftwarePlatformsSize() == 0 ? "Unknown platforms" : String.join(" ", component.getSoftwarePlatforms()); + String platforms = component.getSoftwarePlatformsSize() == 0 ? "N/A" : String.join(" ", component.getSoftwarePlatforms()); row.addNewTableCell().setText(platforms); } } @@ -376,13 +405,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}; @@ -390,7 +417,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 bf891ef167d25015bd98e5e825b1e98c5cd4f424..3f37843ae1f05638aef83d5c652f81dae6e1f9d7 100644 GIT binary patch delta 10628 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 delta 9579 zcmaiaWmFzb5-#rU?oMzG?)Ksmg1fsrgIjQScPF@o;1Jvi?t$R$;U@d--TijY-gEm$ zO;2@oPoJvl>3*u~#IW}xvN8w~3JVMl4h~GZk+}gG6&&*SGl>+O5*V}ZC&QAse?>qv zBNX46_kzQ`EvTj7Qe7|YjOdF|Fe8D$pau+PWonn!*Nvnsw#1e!*3D=yM77ikWEGWR zq&`;2s} zU#Ay4)C&?N2Usx10tE5{YGQIoKj5T-h&o9k><1R;f8jFJv~95X&f}(eMla^;4O6m4 zy$!8MZ7j$^GSZl_d&`n$A180Iorc)Wr-d(VV(1=F<^346EE>P;decpQc1}fxc)p2n zKtsnY96h`&=X=jgN3wI6%7eBXy|XIfu{c(Iu6D*fTbAm>EMxqH$(^HwgN2F$bD%hQ zH{p~(22DT8%3ZIT_ao*ZzxzF{@u+|y zm>7@ICWR7XkPd9nhJ1lfnq^EYz3?kvDHNj(^n1P_$+;bx-OQ_%uZP%cP3VFe^aGoz{(y{Zlh z-wEJi3qlZ*8`CAA@|scP&FX|KGZ4+F*H!v8tdvlG2B!o&_H0T&7pFY^g7?o7W?E4Z zugKJJ5|MPb4snJY4}|LiKmB$)ZgX|fmR(?smBdNqlpaqldvqE?bL0~SbUPq*0&U!q z{keg0&>!uK-G7AWxjm~=?7~s^H%5asv%W!i6Zc?C}fEyA`XFur$`ujH- z4gVE|`nMKW8H?Vou zDuO4v8O99U&1l&K_AMGrzFo|{%nyAyAs2>df)W-Ow5UmcC@bI+CqY`xH9;rZk)3a; z_lTm!92Ps0W}Fb6)NZ6hP~^|yoP$S+SDK?q_hc;;9&Ji8ZI?U#X&Ghg4(Dtnu}V0Z zO*Ss)Q(pPj>(Y3C;AWj;VhjtVLx)69F2GZ<6dViW;TAD)@r{2Qb%AoTZh_Bc(P&?Z zucB(8W7B11cNl`VladqEM_^LYAW7lL?ghgxQD|j6wFufJW1MLGd9xV2XG6pq1??&^ z9D6K*xN%viQrVzaMKV{d zXD-ede{Ffh+r?#g2^DVG47IyS96ijP;ZD4?(lVom=a=l+%zNt1xwk!=`&3%zog{-RWWeyRpDFNsU%g0V~!Owk`a+|pUwb0JNcN7$Vu43JM6v#@b3?> zP@xe5`HS!2$RcqJ9~cc?(D~*{Bx~juwjo#Psk+rS-ghO_+0rko)}w;z@h1QT=rr!v z`!UDc?@7)sUZ`ia%mE+O`9j@mW*fBYmehx@=tGj<)4RZuyF}W?u=Gn;eqxCwv`o&O zVbmcR!7ny_N;7+6(^Fu-o?tEHpv@c`O^p${vDA?&VkBJW{k1eBbIL%ep`oBbh%~!T zsKuBLKZNReMmd{X8!4x<%D(|*71ze9bE*FP!cnnmyiSu6hZSss6>Lmglu~WdG<=+X zO$reNh<}(jkCJ27Eyj~&Tan0mNj$*@*-;E``CvdQrdJP`J#l{!Mpc4OoEK5ODL$;R z$@hI54O1C}Qv69yj}#Ny>*kvbVNJCC;c2hBB&*8{mXR^bswmRNV3G__vpH(@Va70# z$XecEDV-Yg&^=bCv9_Lp`-X?!F1=ak;^^k|hT{8p{Pw~>G?RyWa}Ijm9cHmxRm{Dx zE8V%ZuuTeJB}X7D$WQ8i5lE5#ky(hc61DOnChGOf;*|dCv@pphHw8|2pJca@{_^p8 z@CPo;mYGp^1O)>VTxc1<@;+q=yK!9MqG8%n)v|b+C}7&RvZ-5+IZf9eN!Ney;1fE3 z+idjGv3xL99Y|joO24Q7?9*9kMkQZ4IdcaVEvAfcNS74&~(&@J31G^AWAK&m%9@_<_*Ay`KV2b(oQjWjmTCkPFD&2d+n23Ks#I$T^_}OyCmA~z zE85q+cKKkF=};SJ{nhE9DD>0nQ#JnQFJA^XJ>zmVXC#S?HllZ=pD%}55%iT74cVrFExTuE3Fs=o!s@3*YWVp>sAR5*Q356i`pvyGg1d4Jl@($DudrUgHFO~ zqdB`Re!k{bGVZ(_vxfKw|CUnLU}WsoyN?wOYnsQJJhBq*%3}h&#-IS%a8MnKY(PwbxT11n4)!&$mJpjd z;_LKbMKhQrfZbbQPUi-ufDKMjM6TD91zF;7$9VM#t)VP>{!0Y`7JhRj8ydOs5)po7 zDPHAw&8n+UU^9o6w?oPUp)?D$>%Af~&)V3p5(3M|!a_!Bm57q>c$KC2j@v7kCbU3T zpLpXx7>E;EQ{1U>*_m4UDI8a<+qV{i6>y)$aW>X50+2PERrz0NjC)q_@+0x;KZl6v zAWOhkQpl@>(u=(^*atAo*H4~APN1t z^l31eZ;3>QA~Q;5!>RZrUGCUdw+-(Z2cJGbRpy@o)g1V%EtW;8CU#ms^7X>fM+|)@7l`ZxwwjrNy zuxMPcfZot*bb@WR&iP!mPIX?@kIWmBlB1P3}wl-V&D4oN%XC+Ktbux%A8w=OAO zrqd;5=aj9s2(G%xa~=WV1PeTxhv4nJTi|DPZKH?$`RmL9vDS%5JE_T%+Y0kWF!IA< zM&UHPn3j@L(#yd!Wc=xAb=7cjdDtGJ4VdOXt^`gX50rGJn$Dci?O+Ks%d~g}98lKV8vyIa zyFbV5|1HSOP_X_2(ng414SgcJet-a$T}Z~^2OXl^1=3p0l4+nbMfdX%3r4|SL_}lZ zEo#Sianr#NWL@^^y8O}oFA{m=S*T{?j|d$J29lV4@KJYATT`MBO@y_OYH-V>ta?fT z#4h{F)FH4;I{hOIb5on}1>}`U%ZC6q z!VA+#Hg}4?$ap~j(iWga+MzRp{{~JTMNt{PQ9Z(^_DCLt&e*E_mfi&(>F~aj46R`V z94A&5%f50KHQdBMG(<#L+tvQ+k$~q`Y*>8H@+0+SQJG7lRn(ay5rwc(mX}nZ@6Z!W ze$o;A!_?cWut*4N_1BPmQ{=Q^@QeJ3U9f3WeLIMr;E8gyFRfi5 zKNMN81I2$(K)mb$+(|hEzOyEK_$YrJ5oc|{ms7xnn2osi9hPg;(eiuD@YqY=u!jUh z#AjDM;aGfhJj41=UmL%ox334iy38b_JV8LoKT5n)hw>1TbD_MDhG7wyhYH15QvB!; zt(y&ouA@xG;&=%JIia3X*r1IW(`G$Jyi{yMnAA0L*LW{}=s(HOJNzj0ac#z?NK0q1 z`QT`>{X+YChi=-#rRp*DlAF(_n65{oOUJ#@)v3m_HF{{QH7f1EpyNXqRd?e``sB+I z;ukJ8*$k)KhJrLfZW!;L^70e!v&okV5yP$_j61$WLsouZi&=#=_1*k?7SBfIcQ5%` zEe#Aq0k&!!{8zBzV@{LWJd=1OYE$HDB)X(})3K>k)Dq)SxgtCg*i%uE!62oajwv}8 z4#Hba^+ZENwb|3j&wb|8L)VEReD^VU-;+vA5{?>qeYQ-5h0SPY_jKmY;EtNCBN=C+ za=hHi8Dbp)j4&!BS-eEnCTyg2D))96yn!;c;ZLH{M7T=ETbE-k17Bm<&_W`u(9t+W zLv*OU&}Q*h)4pi)lc@)#RhXE^5Rl-q*+?11V7hMn#3!n zxA;_J1GhYDD#ns&j_V2OD#i5ov{pm$=FxuXY|I>*KGPQv67Z53QB+v6bSu3F?ip2S zA*Ara82(f*0>UqAA^<_ZRsZ{GHlM{2Jv;cIx{qztaEq|LQ_Ru7;jmfhT=%IaX#{rX z+V~o4a(kDi=OMlqdAPBwW3Ru0)h8Jg6P7jj#d zC&k>-Os*->l6pq2aG|kiK~??n)BHFC?MIByRHm{cd?I{ohQ>>RoI&OG=Mm&`PuMaM zfPnQ(8k!a?J6`d_*VY|To%e8?EXv!__)}8sa z534y177L#JGO1nf#p8`9^b|XE+4A9|*UO>dTH_OJ_?wRuSYv;h$pptW?D^u+KMM6* zeIx31eefwvR#yO3XL3As|Hiwd^1@_QJw~cc? zHaVyl3h^flde>6P8NrOQs$sxyn(i(b3D)DjATn{7b9Y?7LHr3nJ^R{S5MY3Teg64h zu|P$zzZJCKbq@z;Qx;3JBpo6|VDwLnFzj3))XYgCi7X^uauzh`458u)w&a9!QQD9+ z-8!t5DZ*F~p>O+r_bm&c$>_XI!z$l4WURp;s-uW*Gv=#OPuRL|ecr;MJTCuMJ{?8t zImM)3hU>vZ&mp2;{cZ-nRup|qj=2KabWlVmr!&Ax)-_i%I*yP8JAMn8eJ|eUh*i_H z{cYG8Igt+tp&+6noUk5EL98o0q=8~Czy4sSh3}Kk1?)Q%^LE*!nc8ug!f@^`K9R_< z?WHuSV$#IoV68dPglZ+ehg|t3^SC-<4mT;`6O?UR-4)Z|BRF`ya~RReRI$xb!y9)8 z*1-*%X$q=L!4k5Wa~lU9SURdC_V4_*8!H~31T=>QpGoVU0V+zR&{+|WzNrA%f=Ob< zSG;t8uR#CRj_$2;YGiD9|2@v#fPQ9(^;9^E~@HaPW4bD6tsQweK**+NlIMwe(O--@t|YMCXOnic}zjnquga!M|qqndCM}p;x&jcC94C6 zs5Dd&;hp7i_e7E@2EY^pP3+t(I_T>;K!Z=+8g`Clnb)N-=K&vND%A8-+h{#-F{g5q z-fMX&Ppz5fqZTJoHX;e#`$Y};LrNOZ6dtd0EP{{XK7!U;@!nL-TI^`Xp*~rh-8*r@ zBp*oXi_bUs4(sfQ95r6Vrz8`TB$iQm95u!deilV0++8y@@j%~sc<+zW&s9rqw`+}K zo|n%m0&i=U!M2S3_;6$xokeE6Fz#*Djvp8OSpsjohD}A!qb~zEBQqRc&?IM?{E>{+ zsjvA|E+lKG{IbbCQZJP^DR{r4ShgD@$G1(yWdXExX15JyGO-?6-N^Y&oZF2g+=`cT zcm+Ab$O2D^)fz%;00F~P1BlPj5T6}&CSJ|iz&tGuzT=7V?e|8b_D1T{Bjg*2QukId zs0objnDSzeUVNeheuv&+;ZhK~e)Rt~tuf4hEx#lfGIAhGPi>VKEA0GU)6-W8bF>8` zy)-8krE#3KzHyo~e_3v4FtsaHJio`E8VI3kL6wE`aX0r-*`WlwyyI?0pmL@R^5zD- zFxq2NvfK9Nrrko2G_b}V2VNf?-MHO}^&IgpC1ly03_{#{{2x!Re~RI;L?; zFrbGe=?<{r9XgV$)(Th1%gk}Bd3{54NuPpcOp(^A6)R|N_sc{&bR2=9k1JVS3wx*` zEOAO_tT7)fQ!atz${H-7b1-A3?Y~mXgZnGCV z-pm@4WsyfUGrRt5elh9~;^PnO^i6`}ZzIS3PeA#LQ;BIo&I0t35s}hbmM4R=iw|{< zPr@+A5+~Ca+4VW9Hs&u!=}K#)?NO9JazUrMmsA;77c;qNKO=pr5Hy-!(3Etq-cOl$ z80P(=bGB0S-WeSz(U5u5h7D8LQ>`=c#|E`!^RSUm`ENLUdTi$H>}oEsBEsMQ^lgW62l~@Z=o+OE#F|n*L zK|g$q`PEP3z`Gu&zT@Lyg0@~J)IJ0KZVUfJb2C2>sz8R`Sa@dY_Xej}NXy{srR!@H?kW*z1)mEP{yHFGAHIy&jEyS%=TT*+(zt#sj+JJ4fgeKe^H?_tS5x*xeNjujbhC;fi6)<0oy#l%` za7m%4LNH~ld^+O*im*aUC^~`yIs(Y3A-bqZaLFHZQ6p$#duY;_5q3oOm~d-Q;cHN0 zJiSIdfm;fWhYDoAm_+`Va9dE}TTo)Wy+*u&WQvY-ie%B4M6qfSyIA47Silair1u+) z!B;077O|si*!`C>E7blF|&Z zr{%==IY|YLz$&F}ReXg{;*Ht)$M!UVM)C5Jw#c58o3+A+Op1Jqjm|p0_vVjtkGJP2!Qq__ep{RhC;-${tDO2%nD{$8r>L5s zsYx2VD?av|Y1I?_2^^Yo z*u<0b+i#5=s4cwR8T6--#yUA}*U~lK=NOxv`6(*})OMZc;mo#mb*XMGo7xjA-L^tU zEN}nVf+j4tAU^!wegs7SYYS3LLZqbxv=w4kSg|(lvFI>BGBWH~1@J|3zu}oB&aAz38EMmyF1SW1o%XK{86kX5^UcpaiStVK57} zqU=&*G&O+|tIWZA?K}MHiQdlSG)`t#Dr1j#!EkWjc?`_nZ=Sa-=JX7WWQ=a~1|h;2 zU$%Vh9%@~Rgla$%wV~3>(4`m#7@07nXo~HS;}M)wn0l~vpzen>(df1q^PoIqQQ_gE zIgq9&sXe-b?_mu9SJs}$dnqV272>Ph3Tn#88~Vmd8Gl{y&+h;WrNMTMe4VrFw$K?X zriZdt)|2NPkL|ogNyiVk{r=Nll)W=jnS&UQW$WL)5=v1&G$hgrei!=zl!PCo`kUDw znYe%ed;25IBsmX4`8%D=Yo+}6;^pH+9iNj;=|@!)OQ=AyZgL2drNxqgXjn=ux4XNo z+&S=Cpk|V<4E5G*Wx7IazrOVP84@Gx*946v^!#a z?N{~h`SOr{rKC>FwI;x|cBi-t;lD(tuFJKuB^8{8wqK8;J!ne-jO$WDt#;?Pzq>}J z<7{7MMBm|}390ypeDMGHXtW=mLi)GL3uRL8H&jO9U$Bp&a^FRNo@a1z%0POzM!!%` z2kW#Deu6MD&v;QlB1Hlk9J!#y_PbHMI7PH#r%#HSGifP}j_ZTfx7cP;D zAV1J%dPsY}D-bQtpGo`27%;>iDWS4%$@c9ttdWS8fBdCzf|EuGl@NbBn`OWLKv5VP zZN4_w04=OX^#oJ8rFQ`mMwZc-P&RlLfhlsX<5DBE-o?9Jif+gvSC6jS3PEfFY*W9k z%^=PC**3;V!4pE)jf|AJ?&_IlEv1GM(gl8;=BUHCa?NJ3ygqZ68_P;L^=TuVD(Rf- zF3G&c?PhV$xK3w`r;IWzbRBK%G{WzzFH)t7yAUAUob{2(eaUvdpRLcRSzF%9)F0|+ zwhjDWph4Ypq(YWg(0}wD^Ho1w?)RZr4f?*dC8GZjp-vKJX8cFmkR3B2xM5P{KYRQg z1^?%u)=4AGWMqFn{C5=g2M_(15&CnUPhw`lfv_P+l42pz`@{SD4;J;` zy?)nhf6wk8u-e7d%ht^0Pez9_2pj?n>|Z$`ihuXb-!T1e<&7e#m*uai{avB|DMUb% l1kU=G5E1C>nc{D)@BY?0=HJEv11qLY5@n@^;h_J+{XYPM$|C>( 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 80515e0b04..6158eca7ed 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 @@ -284,8 +284,9 @@ private void downloadLicenseInfo(ResourceRequest request, ResourceResponse respo } private void sendLicenseInfoResponse(ResourceRequest request, ResourceResponse response, Project project, LicenseInfoFile licenseInfoFile) throws IOException { - OutputFormatInfo outputFormatInfo = licenseInfoFile.getOutputFormatInfo(); - String filename = String.format("LicenseInfo-%s%s-%s.%s", project.getName(), + OutputFormatInfo outputFormatInfo = licenseInfoFile.getOutputFormatInfo(); + String documentVariant = licenseInfoFile.getOutputFormatInfo().getVariant() == OutputFormatVariant.DISCLOSURE ? "LicenseInfo" : "ProjectClearingReport"; + String filename = String.format("%s-%s%s-%s.%s", documentVariant, project.getName(), StringUtils.isBlank(project.getVersion()) ? "" : "-" + project.getVersion(), SW360Utils.getCreatedOnTime().replaceAll("\\s", "_").replace(":", "_"), outputFormatInfo.getFileExtension()); diff --git a/frontend/sw360-portlet/src/main/webapp/html/components/editRelease.jsp b/frontend/sw360-portlet/src/main/webapp/html/components/editRelease.jsp index 95c21f6ddb..ee8c9b2716 100644 --- a/frontend/sw360-portlet/src/main/webapp/html/components/editRelease.jsp +++ b/frontend/sw360-portlet/src/main/webapp/html/components/editRelease.jsp @@ -53,6 +53,7 @@ + @@ -176,6 +177,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 b922ab8e80..f20288d3cb 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 @@ -15,7 +15,7 @@ - + @@ -37,21 +37,28 @@ - - - +
Release SummaryRelease Summary
+ + "/> + + + "/> + operatingSystems, 54: optional COTSDetails cotsDetails, 55: optional EccInformation eccInformation, + 56: optional set softwarePlatforms, 65: optional set mainLicenseIds, diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/project/ProjectController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/project/ProjectController.java index 4c5fe054ac..2bcc82c2b8 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/project/ProjectController.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/project/ProjectController.java @@ -28,6 +28,7 @@ import org.eclipse.sw360.datahandler.thrift.licenseinfo.LicenseInfoFile; import org.eclipse.sw360.datahandler.thrift.licenseinfo.LicenseNameWithText; import org.eclipse.sw360.datahandler.thrift.licenseinfo.OutputFormatInfo; +import org.eclipse.sw360.datahandler.thrift.licenseinfo.OutputFormatVariant; import org.eclipse.sw360.datahandler.thrift.licenses.License; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.projects.ProjectRelationship; @@ -282,9 +283,10 @@ public void downloadLicenseInfo(@PathVariable("id") String id, final String projectName = sw360Project.getName(); final String projectVersion = sw360Project.getVersion(); - final String timestamp = SW360Utils.getCreatedOnTime().replaceAll("\\s", "_").replace(":", "_"); - final OutputFormatInfo outputFormatInfo = licenseInfoService.getOutputFormatInfoForGeneratorClass(generatorClassName); - final String filename = String.format("LicenseInfo-%s%s-%s.%s", projectName, + final String timestamp = SW360Utils.getCreatedOnTime().replaceAll("\\s", "_").replace(":", "_"); + final OutputFormatInfo outputFormatInfo = licenseInfoService.getOutputFormatInfoForGeneratorClass(generatorClassName); + final String variant = outputFormatInfo.variant == OutputFormatVariant.DISCLOSURE ? "LicenseInfo" : "ProjectClearingReport"; + final String filename = String.format("%s-%s%s-%s.%s", variant, projectName, StringUtils.isBlank(projectVersion) ? "" : "-" + projectVersion, timestamp, outputFormatInfo.getFileExtension());