Skip to content

Commit d796ddc

Browse files
feat(resourceserver): add FOSSology status endpoint for release
Signed-off-by: Sandip Mandal <sandipsmmandal02@gmail.com>
1 parent ceec3d0 commit d796ddc

2 files changed

Lines changed: 222 additions & 0 deletions

File tree

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright Siemens AG, 2025. Part of the SW360 Portal Project.
3+
* Copyright Sandip Mandal<sandipmandal02.sm@gmail.com>, 2026.
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*/
10+
package org.eclipse.sw360.rest.resourceserver.release;
11+
12+
import com.fasterxml.jackson.annotation.JsonInclude;
13+
import com.fasterxml.jackson.annotation.JsonProperty;
14+
15+
import java.util.List;
16+
17+
/**
18+
* Data Transfer Object for FOSSology release information.
19+
* Reflects the three-step FOSSology workflow: upload → scan → report.
20+
*/
21+
@JsonInclude(JsonInclude.Include.NON_NULL)
22+
public class FossologyReleaseInfo {
23+
24+
/**
25+
* Report formats supported by FOSSology, available once scanning is complete.
26+
*/
27+
public static final List<String> REPORT_FORMATS = List.of(
28+
"spdx2", "spdx2tv", "spdx3json", "spdx3rdf", "spdx3jsonld",
29+
"dep5", "readmeoss", "unifiedreport", "clixml", "cyclonedx"
30+
);
31+
32+
@JsonProperty("uploadId")
33+
private String uploadId;
34+
35+
@JsonProperty("uploadStatus")
36+
private String uploadStatus;
37+
38+
@JsonProperty("scanStatus")
39+
private String scanStatus;
40+
41+
@JsonProperty("reportStatus")
42+
private String reportStatus;
43+
44+
@JsonProperty("processStatus")
45+
private String processStatus;
46+
47+
@JsonProperty("sourceAttachmentId")
48+
private String sourceAttachmentId;
49+
50+
@JsonProperty("reportAttachmentId")
51+
private String reportAttachmentId;
52+
53+
@JsonProperty("availableReportFormats")
54+
private List<String> availableReportFormats;
55+
56+
@JsonProperty("lastUpdated")
57+
private String lastUpdated;
58+
59+
public FossologyReleaseInfo() {
60+
}
61+
62+
public String getUploadId() { return uploadId; }
63+
public void setUploadId(String uploadId) { this.uploadId = uploadId; }
64+
65+
public String getUploadStatus() { return uploadStatus; }
66+
public void setUploadStatus(String uploadStatus) { this.uploadStatus = uploadStatus; }
67+
68+
public String getScanStatus() { return scanStatus; }
69+
public void setScanStatus(String scanStatus) { this.scanStatus = scanStatus; }
70+
71+
public String getReportStatus() { return reportStatus; }
72+
public void setReportStatus(String reportStatus) { this.reportStatus = reportStatus; }
73+
74+
public String getProcessStatus() { return processStatus; }
75+
public void setProcessStatus(String processStatus) { this.processStatus = processStatus; }
76+
77+
public String getSourceAttachmentId() { return sourceAttachmentId; }
78+
public void setSourceAttachmentId(String sourceAttachmentId) { this.sourceAttachmentId = sourceAttachmentId; }
79+
80+
public String getReportAttachmentId() { return reportAttachmentId; }
81+
public void setReportAttachmentId(String reportAttachmentId) { this.reportAttachmentId = reportAttachmentId; }
82+
83+
public List<String> getAvailableReportFormats() { return availableReportFormats; }
84+
public void setAvailableReportFormats(List<String> availableReportFormats) { this.availableReportFormats = availableReportFormats; }
85+
86+
public String getLastUpdated() { return lastUpdated; }
87+
public void setLastUpdated(String lastUpdated) { this.lastUpdated = lastUpdated; }
88+
89+
public static Builder builder() {
90+
return new Builder();
91+
}
92+
93+
public static class Builder {
94+
private String uploadId;
95+
private String uploadStatus;
96+
private String scanStatus;
97+
private String reportStatus;
98+
private String processStatus;
99+
private String sourceAttachmentId;
100+
private String reportAttachmentId;
101+
private List<String> availableReportFormats;
102+
private String lastUpdated;
103+
104+
public Builder uploadId(String uploadId) { this.uploadId = uploadId; return this; }
105+
public Builder uploadStatus(String uploadStatus) { this.uploadStatus = uploadStatus; return this; }
106+
public Builder scanStatus(String scanStatus) { this.scanStatus = scanStatus; return this; }
107+
public Builder reportStatus(String reportStatus) { this.reportStatus = reportStatus; return this; }
108+
public Builder processStatus(String processStatus) { this.processStatus = processStatus; return this; }
109+
public Builder sourceAttachmentId(String sourceAttachmentId) { this.sourceAttachmentId = sourceAttachmentId; return this; }
110+
public Builder reportAttachmentId(String reportAttachmentId) { this.reportAttachmentId = reportAttachmentId; return this; }
111+
public Builder availableReportFormats(List<String> formats) { this.availableReportFormats = formats; return this; }
112+
public Builder lastUpdated(String lastUpdated) { this.lastUpdated = lastUpdated; return this; }
113+
114+
public FossologyReleaseInfo build() {
115+
FossologyReleaseInfo info = new FossologyReleaseInfo();
116+
info.setUploadId(uploadId);
117+
info.setUploadStatus(uploadStatus);
118+
info.setScanStatus(scanStatus);
119+
info.setReportStatus(reportStatus);
120+
info.setProcessStatus(processStatus);
121+
info.setSourceAttachmentId(sourceAttachmentId);
122+
info.setReportAttachmentId(reportAttachmentId);
123+
info.setAvailableReportFormats(availableReportFormats == null ? null : List.copyOf(availableReportFormats));
124+
info.setLastUpdated(lastUpdated);
125+
return info;
126+
}
127+
}
128+
129+
@Override
130+
public String toString() {
131+
return "FossologyReleaseInfo{" +
132+
"uploadId='" + uploadId + '\'' +
133+
", uploadStatus='" + uploadStatus + '\'' +
134+
", scanStatus='" + scanStatus + '\'' +
135+
", reportStatus='" + reportStatus + '\'' +
136+
", processStatus='" + processStatus + '\'' +
137+
'}';
138+
}
139+
}

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/release/ReleaseController.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.apache.thrift.TException;
5050
import org.eclipse.sw360.datahandler.common.CommonUtils;
5151
import org.eclipse.sw360.datahandler.common.SW360Constants;
52+
import org.eclipse.sw360.datahandler.common.FossologyUtils;
5253
import org.eclipse.sw360.datahandler.common.SW360Utils;
5354
import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException;
5455
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
@@ -109,6 +110,7 @@
109110
import org.springframework.web.multipart.MultipartFile;
110111
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
111112

113+
112114
import com.fasterxml.jackson.databind.DeserializationFeature;
113115
import com.fasterxml.jackson.databind.ObjectMapper;
114116
import com.google.common.collect.ImmutableMap;
@@ -2196,4 +2198,85 @@ public ResponseEntity<Map<String, Object>> getUsageInformationForReleaseMerge(
21962198
Map<String, Object> result = new HashMap<>(usageInfo);
21972199
return new ResponseEntity<>(result, HttpStatus.OK);
21982200
}
2201+
2202+
@Operation(
2203+
summary = "Get FOSSology processing information for a release.",
2204+
description = "Returns the FOSSology workflow status for a release, covering all three steps: " +
2205+
"upload, scan, and report. Also lists available report formats once scanning is complete, " +
2206+
"and the SW360 attachment ID of any downloaded report.",
2207+
tags = {"Releases"},
2208+
responses = {
2209+
@ApiResponse(
2210+
responseCode = "200",
2211+
description = "FOSSology information retrieved successfully",
2212+
content = @Content(mediaType = "application/json",
2213+
schema = @Schema(implementation = FossologyReleaseInfo.class))
2214+
),
2215+
@ApiResponse(
2216+
responseCode = "404",
2217+
description = "Release not found"
2218+
)
2219+
}
2220+
)
2221+
@GetMapping(value = RELEASES_URL + "/{id}/fossology")
2222+
public ResponseEntity<FossologyReleaseInfo> getFossologyInfo(
2223+
@Parameter(description = "The ID of the release.")
2224+
@PathVariable("id") String releaseId) throws TException {
2225+
2226+
User user = restControllerHelper.getSw360UserFromAuthentication();
2227+
restControllerHelper.throwIfSecurityUser(user);
2228+
Release release = releaseService.getReleaseForUserById(releaseId, user);
2229+
2230+
return ResponseEntity.ok(buildFossologyReleaseInfo(release));
2231+
}
2232+
2233+
private FossologyReleaseInfo buildFossologyReleaseInfo(Release release) {
2234+
FossologyReleaseInfo.Builder builder = FossologyReleaseInfo.builder();
2235+
2236+
ExternalToolProcess process = releaseService.getExternalToolProcess(release);
2237+
if (process == null) {
2238+
return builder.build();
2239+
}
2240+
2241+
builder.processStatus(process.getProcessStatus().name());
2242+
2243+
if (process.isSetAttachmentId()) {
2244+
builder.sourceAttachmentId(process.getAttachmentId());
2245+
}
2246+
2247+
boolean scanDone = false;
2248+
if (process.getProcessSteps() != null) {
2249+
for (ExternalToolProcessStep step : process.getProcessSteps()) {
2250+
String stepName = step.getStepName();
2251+
ExternalToolProcessStatus stepStatus = step.getStepStatus();
2252+
if (stepStatus == null) {
2253+
continue;
2254+
}
2255+
if (FossologyUtils.FOSSOLOGY_STEP_NAME_UPLOAD.equals(stepName)) {
2256+
builder.uploadStatus(stepStatus.name());
2257+
if (stepStatus == ExternalToolProcessStatus.DONE && step.getResult() != null) {
2258+
builder.uploadId(step.getResult());
2259+
}
2260+
} else if (FossologyUtils.FOSSOLOGY_STEP_NAME_SCAN.equals(stepName)) {
2261+
builder.scanStatus(stepStatus.name());
2262+
scanDone = stepStatus == ExternalToolProcessStatus.DONE;
2263+
} else if (FossologyUtils.FOSSOLOGY_STEP_NAME_REPORT.equals(stepName)) {
2264+
builder.reportStatus(stepStatus.name());
2265+
if (stepStatus == ExternalToolProcessStatus.DONE && step.getResult() != null) {
2266+
builder.reportAttachmentId(step.getResult());
2267+
}
2268+
}
2269+
}
2270+
}
2271+
2272+
if (scanDone) {
2273+
builder.availableReportFormats(FossologyReleaseInfo.REPORT_FORMATS);
2274+
}
2275+
2276+
if (release.isSetModifiedOn()) {
2277+
builder.lastUpdated(release.getModifiedOn());
2278+
}
2279+
2280+
return builder.build();
2281+
}
21992282
}

0 commit comments

Comments
 (0)