/*
* Copyright Siemens AG, 2013-2017. Part of the SW360 Portal Project.
* With contributions by Bosch Software Innovations GmbH, 2016.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.sw360.portal.portlets.components;
import com.google.common.collect.ImmutableList;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.portlet.PortletResponseUtil;
import com.liferay.portal.kernel.servlet.SessionMessages;
import org.eclipse.sw360.datahandler.common.CommonUtils;
import org.eclipse.sw360.datahandler.common.SW360Constants;
import org.eclipse.sw360.datahandler.common.SW360Utils;
import org.eclipse.sw360.datahandler.common.ThriftEnumUtils;
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.thrift.*;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;
import org.eclipse.sw360.datahandler.thrift.components.*;
import org.eclipse.sw360.datahandler.thrift.cvesearch.CveSearchService;
import org.eclipse.sw360.datahandler.thrift.cvesearch.VulnerabilityUpdateStatus;
import org.eclipse.sw360.datahandler.thrift.projects.Project;
import org.eclipse.sw360.datahandler.thrift.projects.ProjectService;
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.vendors.VendorService;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.ReleaseVulnerabilityRelation;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityService;
import org.eclipse.sw360.exporter.ComponentExporter;
import org.eclipse.sw360.portal.common.*;
import org.eclipse.sw360.portal.portlets.FossologyAwarePortlet;
import org.eclipse.sw360.portal.users.LifeRayUserSession;
import org.eclipse.sw360.portal.users.UserCacheHolder;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import javax.portlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.base.Strings.nullToEmpty;
import static org.eclipse.sw360.datahandler.common.CommonUtils.nullToEmptyList;
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.portal.common.PortalConstants.*;
import static org.eclipse.sw360.portal.common.PortletUtils.addToMatchedByHistogram;
import static org.eclipse.sw360.portal.common.PortletUtils.getVerificationState;
/**
* Component portlet implementation
*
* @author cedric.bodet@tngtech.com
* @author Johannes.Najjar@tngtech.com
* @author stefan.jaeger@evosoft.com
* @author alex.borodin@evosoft.com
*/
public class ComponentPortlet extends FossologyAwarePortlet {
private static final Logger log = Logger.getLogger(ComponentPortlet.class);
private boolean typeIsComponent(String documentType) {
return SW360Constants.TYPE_COMPONENT.equals(documentType);
}
@Override
protected Set<Attachment> getAttachments(String documentId, String documentType, User user) {
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
if (typeIsComponent(documentType)) {
Component component = client.getComponentById(documentId, user);
return CommonUtils.nullToEmptySet(component.getAttachments());
} else {
Release release = client.getReleaseById(documentId, user);
return CommonUtils.nullToEmptySet(release.getAttachments());
}
} catch (TException e) {
log.error("Could not get " + documentType + " attachments for " + documentId, e);
}
return Collections.emptySet();
}
private static final ImmutableList<Component._Fields> componentFilteredFields = ImmutableList.of(
Component._Fields.NAME,
Component._Fields.CATEGORIES,
Component._Fields.LANGUAGES,
Component._Fields.SOFTWARE_PLATFORMS,
Component._Fields.OPERATING_SYSTEMS,
Component._Fields.VENDOR_NAMES,
Component._Fields.COMPONENT_TYPE,
Component._Fields.MAIN_LICENSE_IDS);
//! Serve resource and helpers
@Override
public void serveResource(ResourceRequest request, ResourceResponse response) throws IOException, PortletException {
String action = request.getParameter(PortalConstants.ACTION);
if (VIEW_VENDOR.equals(action)) {
serveViewVendor(request, response);
} else if (ADD_VENDOR.equals(action)) {
serveAddVendor(request, response);
} else if (DELETE_COMPONENT.equals(action)) {
serveDeleteComponent(request, response);
} else if (DELETE_RELEASE.equals(action)) {
serveDeleteRelease(request, response);
} else if (SUBSCRIBE.equals(action)) {
serveSubscribe(request, response);
} else if (SUBSCRIBE_RELEASE.equals(action)) {
serveSubscribeRelease(request, response);
} else if (UNSUBSCRIBE.equals(action)) {
serveUnsubscribe(request, response);
} else if (UNSUBSCRIBE_RELEASE.equals(action)) {
serveUnsubscribeRelease(request, response);
} else if (PortalConstants.VIEW_LINKED_RELEASES.equals(action)) {
serveLinkedReleases(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)){
updateVulnerabilityVerification(request,response);
} else if (PortalConstants.EXPORT_TO_EXCEL.equals(action)) {
exportExcel(request, response);
} else if (isGenericAction(action)) {
dealWithGenericAction(request, response, action);
}
}
@Override
protected void dealWithFossologyAction(ResourceRequest request, ResourceResponse response, String action) throws IOException, PortletException {
if (PortalConstants.FOSSOLOGY_SEND.equals(action)) {
serveSendToFossology(request, response);
} else if (PortalConstants.FOSSOLOGY_GET_STATUS.equals(action)) {
serveFossologyStatus(request, response);
}
}
private void serveViewVendor(ResourceRequest request, ResourceResponse response) throws IOException, PortletException {
String what = request.getParameter(PortalConstants.WHAT);
String where = request.getParameter(PortalConstants.WHERE);
if ("vendor".equals(what)) {
renderVendor(request, response, where);
} else if ("vendorSearch".equals(what)) {
renderVendorSearch(request, response, where);
}
}
private void renderVendorSearch(ResourceRequest request, ResourceResponse response, String searchText) throws IOException, PortletException {
List<Vendor> vendors = null;
try {
VendorService.Iface client = thriftClients.makeVendorClient();
if (isNullOrEmpty(searchText)) {
vendors = client.getAllVendors();
} else {
vendors = client.searchVendors(searchText);
}
} catch (TException e) {
log.error("Error searching vendors", e);
}
request.setAttribute("vendorsSearch", nullToEmptyList(vendors));
include("/html/components/ajax/vendorSearch.jsp", request, response, PortletRequest.RESOURCE_PHASE);
}
private void renderVendor(ResourceRequest request, ResourceResponse response, String vendorId) throws IOException, PortletException {
Vendor vendor = null;
if (vendorId != null && !vendorId.isEmpty()) {
try {
VendorService.Iface client = thriftClients.makeVendorClient();
vendor = client.getByID(vendorId);
} catch (TException e) {
log.error("Error getting vendor from backend", e);
}
}
if (vendor == null) {
vendor = new Vendor();
vendor.setFullname("This is a vendor");
vendor.setShortname("It really is");
}
request.setAttribute("vendor", vendor);
include("/html/components/ajax/vendorAjax.jsp", request, response, PortletRequest.RESOURCE_PHASE);
}
private void serveAddVendor(ResourceRequest request, ResourceResponse response) throws IOException, PortletException {
final Vendor vendor = new Vendor();
ComponentPortletUtils.updateVendorFromRequest(request, vendor);
try {
VendorService.Iface client = thriftClients.makeVendorClient();
String vendorId = client.addVendor(vendor);
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
jsonObject.put("id", vendorId);
try {
writeJSON(request, response, jsonObject);
} catch (IOException e) {
log.error("Problem rendering VendorId", e);
}
} catch (TException e) {
log.error("Error adding vendor", e);
}
}
private void serveDeleteComponent(ResourceRequest request, ResourceResponse response) throws IOException {
RequestStatus requestStatus = ComponentPortletUtils.deleteComponent(request, log);
serveRequestStatus(request, response, requestStatus, "Problem removing component", log);
}
private void serveDeleteRelease(PortletRequest request, ResourceResponse response) throws IOException {
final RequestStatus requestStatus = ComponentPortletUtils.deleteRelease(request, log);
serveRequestStatus(request, response, requestStatus, "Problem removing release", log);
}
private void exportExcel(ResourceRequest request, ResourceResponse response) {
try {
boolean extendedByReleases = Boolean.valueOf(request.getParameter(PortalConstants.EXTENDED_EXCEL_EXPORT));
List<Component> components = getFilteredComponentList(request);
ComponentExporter exporter = new ComponentExporter(thriftClients.makeComponentClient(), extendedByReleases);
PortletResponseUtil.sendFile(request, response, "Components.xlsx", exporter.makeExcelExport(components),
CONTENT_TYPE_OPENXML_SPREADSHEET);
} catch (IOException | SW360Exception e) {
log.error("An error occurred while generating the Excel export", e);
}
}
private void serveSubscribe(ResourceRequest request, ResourceResponse response) {
final RequestStatus requestStatus = ComponentPortletUtils.subscribeComponent(request, log);
serveRequestStatus(request, response, requestStatus, "Problem subscribing component", log);
}
private void serveSubscribeRelease(ResourceRequest request, ResourceResponse response) {
final RequestStatus requestStatus = ComponentPortletUtils.subscribeRelease(request, log);
serveRequestStatus(request, response, requestStatus, "Problem subscribing release", log);
}
private void serveUnsubscribe(ResourceRequest request, ResourceResponse response) {
final RequestStatus requestStatus = ComponentPortletUtils.unsubscribeComponent(request, log);
serveRequestStatus(request, response, requestStatus, "Problem unsubscribing component", log);
}
private void serveUnsubscribeRelease(ResourceRequest request, ResourceResponse response) {
final RequestStatus requestStatus = ComponentPortletUtils.unsubscribeRelease(request, log);
serveRequestStatus(request, response, requestStatus, "Problem unsubscribing release", log);
}
private void serveLinkedReleases(ResourceRequest request, ResourceResponse response) throws IOException, PortletException {
String what = request.getParameter(PortalConstants.WHAT);
String projectId = request.getParameter(RELEASE_ID);
if (PortalConstants.LIST_NEW_LINKED_RELEASES.equals(what)) {
String[] where = request.getParameterValues(PortalConstants.WHERE_ARRAY);
serveNewTableRowLinkedRelease(request, response, where);
} else if (PortalConstants.RELEASE_SEARCH.equals(what)) {
String where = request.getParameter(PortalConstants.WHERE);
serveReleaseSearchResults(request, response, where);
} else if (PortalConstants.RELEASE_SEARCH_BY_VENDOR.equals(what)) {
String where = request.getParameter(PortalConstants.WHERE);
serveReleaseSearchResultsByVendor(request, response, where);
}
}
private void serveNewTableRowLinkedRelease(ResourceRequest request, ResourceResponse response, String[] linkedIds) throws IOException, PortletException {
final User user = UserCacheHolder.getUserFromRequest(request);
List<ReleaseLink> linkedReleases = new ArrayList<>();
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
for (Release release : client.getReleasesById(new HashSet<>(Arrays.asList(linkedIds)), user)) {
final Vendor vendor = release.getVendor();
final String vendorName = vendor != null ? vendor.getShortname() : "";
ReleaseLink linkedRelease = new ReleaseLink(release.getId(), vendorName, release.getName(), release.getVersion(), SW360Utils.printFullname(release));
linkedRelease.setReleaseRelationship(ReleaseRelationship.CONTAINED);
linkedReleases.add(linkedRelease);
}
} catch (TException e) {
log.error("Error getting releases!", e);
throw new PortletException("cannot get releases " + Arrays.toString(linkedIds), e);
}
request.setAttribute(RELEASE_LIST, linkedReleases);
include("/html/utils/ajax/linkedReleasesRelationAjax.jsp", request, response, PortletRequest.RESOURCE_PHASE);
}
private void serveReleaseSearchResults(ResourceRequest request, ResourceResponse response, String searchText) throws IOException, PortletException {
serveReleaseSearch(request, response, searchText, false);
}
private void serveReleaseSearchResultsByVendor(ResourceRequest request, ResourceResponse response, String searchText) throws IOException, PortletException {
serveReleaseSearch(request, response, searchText, true);
}
private void serveReleaseSearch(ResourceRequest request, ResourceResponse response, String searchText, boolean searchByVendor) throws IOException, PortletException {
List<Release> searchResult;
try {
ComponentService.Iface componentClient = thriftClients.makeComponentClient();
if (searchByVendor) {
final VendorService.Iface vendorClient = thriftClients.makeVendorClient();
final Set<String> vendorIds = vendorClient.searchVendorIds(searchText);
if (vendorIds != null && vendorIds.size() > 0) {
searchResult = componentClient.getReleasesFromVendorIds(vendorIds);
} else {
searchResult = Collections.emptyList();
}
} else {
searchResult = componentClient.searchReleaseByName(searchText);
}
} catch (TException e) {
log.error("Error searching projects", e);
searchResult = Collections.emptyList();
}
request.setAttribute(PortalConstants.RELEASE_SEARCH, searchResult);
include("/html/utils/ajax/searchReleasesAjax.jsp", request, response, PortletRequest.RESOURCE_PHASE);
}
//! VIEW and helpers
@Override
public void doView(RenderRequest request, RenderResponse response) throws IOException, PortletException {
String pageName = request.getParameter(PAGENAME);
if (PAGENAME_DETAIL.equals(pageName)) {
prepareDetailView(request, response);
include("/html/components/detail.jsp", request, response);
} else if (PAGENAME_RELEASE_DETAIL.equals(pageName)) {
prepareReleaseDetailView(request, response);
include("/html/components/detailRelease.jsp", request, response);
} else if (PAGENAME_EDIT.equals(pageName)) {
prepareComponentEdit(request);
include("/html/components/edit.jsp", request, response);
} else if (PAGENAME_EDIT_RELEASE.equals(pageName)) {
prepareReleaseEdit(request, response);
include("/html/components/editRelease.jsp", request, response);
} else if (PAGENAME_DUPLICATE_RELEASE.equals(pageName)) {
prepareReleaseDuplicate(request, response);
include("/html/components/editRelease.jsp", request, response);
} else {
prepareStandardView(request);
super.doView(request, response);
}
}
private void prepareComponentEdit(RenderRequest request) {
String id = request.getParameter(COMPONENT_ID);
final User user = UserCacheHolder.getUserFromRequest(request);
request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_COMPONENT);
if (id != null) {
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
Component component = client.getComponentByIdForEdit(id, user);
request.setAttribute(COMPONENT, component);
request.setAttribute(DOCUMENT_ID, id);
setAttachmentsInRequest(request, component.getAttachments());
Map<RequestedAction, Boolean> permissions = component.getPermissions();
DocumentState documentState = component.getDocumentState();
addEditDocumentMessage(request, permissions, documentState);
Set<String> releaseIds = SW360Utils.getReleaseIds(component.getReleases());
setUsingDocs(request, user, client, releaseIds);
request.setAttribute(CUSTOM_MAP, component.isSetRoles() ? component.roles : Collections.emptyMap());
} catch (TException e) {
log.error("Error fetching component from backend!", e);
setSW360SessionError(request, ErrorMessages.ERROR_GETTING_COMPONENT);
}
} else {
if(request.getAttribute(COMPONENT) == null) {
Component component = new Component();
request.setAttribute(COMPONENT, component);
setUsingDocs(request, user, null, component.getReleaseIds());
setAttachmentsInRequest(request, component.getAttachments());
SessionMessages.add(request, "request_processed", "New Component");
request.setAttribute(CUSTOM_MAP, Collections.emptyMap());
}
}
}
private void prepareReleaseEdit(RenderRequest request, RenderResponse response) throws PortletException {
String id = request.getParameter(COMPONENT_ID);
String releaseId = request.getParameter(RELEASE_ID);
request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_RELEASE);
final User user = UserCacheHolder.getUserFromRequest(request);
if (isNullOrEmpty(id) && isNullOrEmpty(releaseId)) {
throw new PortletException("Component and Release ID not set!");
}
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
Release release;
if (!isNullOrEmpty(releaseId)) {
release = client.getReleaseByIdForEdit(releaseId, user);
request.setAttribute(RELEASE, release);
request.setAttribute(DOCUMENT_ID, releaseId);
setAttachmentsInRequest(request, release.getAttachments());
putDirectlyLinkedReleaseRelationsInRequest(request, release.getReleaseIdToRelationship());
Map<RequestedAction, Boolean> permissions = release.getPermissions();
DocumentState documentState = release.getDocumentState();
setUsingDocs(request, releaseId, user, client);
request.setAttribute(CUSTOM_MAP, release.isSetRoles() ? release.roles : Collections.emptyMap());
addEditDocumentMessage(request, permissions, documentState);
if (isNullOrEmpty(id)) {
id = release.getComponentId();
}
} else {
release = (Release) request.getAttribute(RELEASE);
if(release == null) {
release = new Release();
release.setComponentId(id);
release.setClearingState(ClearingState.NEW_CLEARING);
request.setAttribute(RELEASE, release);
putDirectlyLinkedReleaseRelationsInRequest(request, release.getReleaseIdToRelationship());
setAttachmentsInRequest(request, release.getAttachments());
setUsingDocs(request, null, user, client);
request.setAttribute(CUSTOM_MAP, Collections.emptyMap());
SessionMessages.add(request, "request_processed", "New Release");
}
}
Component component = client.getComponentById(id, user);
addComponentBreadcrumb(request, response, component);
if (!isNullOrEmpty(release.getId())) { //Otherwise the link is meaningless
addReleaseBreadcrumb(request, response, release);
}
request.setAttribute(COMPONENT, component);
} catch (TException e) {
log.error("Error fetching release from backend!", e);
setSW360SessionError(request, ErrorMessages.ERROR_GETTING_RELEASE);
}
}
private void prepareReleaseDuplicate(RenderRequest request, RenderResponse response) throws PortletException {
String id = request.getParameter(COMPONENT_ID);
String releaseId = request.getParameter(RELEASE_ID);
request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_RELEASE);
final User user = UserCacheHolder.getUserFromRequest(request);
if (isNullOrEmpty(releaseId)) {
throw new PortletException("Release ID not set!");
}
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
String emailFromRequest = LifeRayUserSession.getEmailFromRequest(request);
Release release = PortletUtils.cloneRelease(emailFromRequest, client.getReleaseById(releaseId, user));
if (isNullOrEmpty(id)) {
id = release.getComponentId();
}
Component component = client.getComponentById(id, user);
addComponentBreadcrumb(request, response, component);
request.setAttribute(COMPONENT, component);
request.setAttribute(RELEASE_LIST, Collections.emptyList());
setUsingDocs(request, null, user, client);
request.setAttribute(RELEASE, release);
request.setAttribute(PortalConstants.ATTACHMENTS, Collections.emptySet());
} catch (TException e) {
log.error("Error fetching release from backend!", e);
}
}
private void prepareDetailView(RenderRequest request, RenderResponse response) {
String id = request.getParameter(COMPONENT_ID);
final User user = UserCacheHolder.getUserFromRequest(request);
if (!isNullOrEmpty(id)) {
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
Component component = client.getComponentById(id, user);
request.setAttribute(COMPONENT, component);
request.setAttribute(DOCUMENT_ID, id);
request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_COMPONENT);
setAttachmentsInRequest(request, component.getAttachments());
Set<String> releaseIds = SW360Utils.getReleaseIds(component.getReleases());
setUsingDocs(request, user, client, releaseIds);
// get vulnerabilities
putVulnerabilitiesInRequestComponent(request, id, user);
request.setAttribute(VULNERABILITY_VERIFICATION_EDITABLE, PermissionUtils.isAdmin(user));
addComponentBreadcrumb(request, response, component);
} catch (TException e) {
log.error("Error fetching component from backend!", e);
setSW360SessionError(request, ErrorMessages.ERROR_GETTING_COMPONENT);
}
}
}
private void setUsingDocs(RenderRequest request, User user, ComponentService.Iface client, Set<String> releaseIds) {
Set<Project> usingProjects = null;
Set<Component> usingComponentsForComponent = null;
if (releaseIds != null && releaseIds.size() > 0) {
try {
ProjectService.Iface projectClient = thriftClients.makeProjectClient();
usingProjects = projectClient.searchByReleaseIds(releaseIds, user);
usingComponentsForComponent = client.getUsingComponentsForComponent(releaseIds);
} catch (TException e) {
log.error("Problem filling using docs", e);
}
}
request.setAttribute(USING_PROJECTS, CommonUtils.nullToEmptySet(usingProjects));
request.setAttribute(USING_COMPONENTS, CommonUtils.nullToEmptySet(usingComponentsForComponent));
}
private void prepareReleaseDetailView(RenderRequest request, RenderResponse response) throws PortletException {
String id = request.getParameter(COMPONENT_ID);
String releaseId = request.getParameter(RELEASE_ID);
final User user = UserCacheHolder.getUserFromRequest(request);
if (isNullOrEmpty(id) && isNullOrEmpty(releaseId)) {
throw new PortletException("Component and Release ID not set!");
}
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
Component component;
Release release = null;
if (!isNullOrEmpty(releaseId)) {
release = client.getReleaseById(releaseId, user);
request.setAttribute(RELEASE_ID, releaseId);
request.setAttribute(RELEASE, release);
request.setAttribute(DOCUMENT_ID, releaseId);
request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_RELEASE);
setAttachmentsInRequest(request, release.getAttachments());
setUsingDocs(request, releaseId, user, client);
putLinkedReleaseRelationsInRequest(request, release.getReleaseIdToRelationship());
if (isNullOrEmpty(id)) {
id = release.getComponentId();
}
putVulnerabilitiesInRequestRelease(request, releaseId, user);
request.setAttribute(VULNERABILITY_VERIFICATION_EDITABLE, PermissionUtils.isAdmin(user));
}
component = client.getComponentById(id, user);
request.setAttribute(COMPONENT, component);
addComponentBreadcrumb(request, response, component);
if (release != null) {
addReleaseBreadcrumb(request, response, release);
}
} catch (TException e) {
log.error("Error fetching release from backend!", e);
setSW360SessionError(request, ErrorMessages.ERROR_GETTING_RELEASE);
}
}
private String formatedMessageForVul(List<VerificationStateInfo> infoHistory){
return CommonVulnerabilityPortletUtils.formatedMessageForVul(infoHistory,
e -> e.getVerificationState().name(),
e -> e.getCheckedOn(),
e -> e.getCheckedBy(),
e -> e.getComment());
}
private void putVulnerabilitiesInRequestRelease(RenderRequest request, String releaseId, User user) throws TException {
VulnerabilityService.Iface vulClient = thriftClients.makeVulnerabilityClient();
List<VulnerabilityDTO> vuls;
if (PermissionUtils.isAdmin(user)) {
vuls = vulClient.getVulnerabilitiesByReleaseId(releaseId, user);
} else {
vuls = vulClient.getVulnerabilitiesByReleaseIdWithoutIncorrect(releaseId, user);
}
request.setAttribute(VULNERABILITY_LIST,vuls);
putVulnerabilityMetadatasInRequest(request, vuls);
}
private void putVulnerabilitiesInRequestComponent(RenderRequest request, String componentId, User user) throws TException{
VulnerabilityService.Iface vulClient = thriftClients.makeVulnerabilityClient();
List<VulnerabilityDTO> vuls;
if (PermissionUtils.isAdmin(user)) {
vuls = vulClient.getVulnerabilitiesByComponentId(componentId, user);
} else {
vuls = vulClient.getVulnerabilitiesByComponentIdWithoutIncorrect(componentId, user);
}
request.setAttribute(VULNERABILITY_LIST, vuls);
putVulnerabilityMetadatasInRequest(request, vuls);
}
private void addToVulnerabilityVerifications(Map<String, Map<String, VerificationState>> vulnerabilityVerifications,
Map<String, Map<String, String>> vulnerabilityTooltips,
VulnerabilityDTO vulnerability){
String vulnerabilityId = vulnerability.getExternalId();
String releaseId = vulnerability.getIntReleaseId();
if(! vulnerabilityVerifications.containsKey(vulnerabilityId)){
vulnerabilityVerifications.put(vulnerabilityId, new HashMap<>());
}
if(! vulnerabilityTooltips.containsKey(vulnerabilityId)){
vulnerabilityTooltips.put(vulnerabilityId, new HashMap<>());
}
ReleaseVulnerabilityRelation relation = vulnerability.getReleaseVulnerabilityRelation();
if (! relation.isSetVerificationStateInfo()) {
vulnerabilityVerifications.get(vulnerabilityId).put(releaseId, VerificationState.NOT_CHECKED);
vulnerabilityTooltips.get(vulnerabilityId).put(releaseId, "Not checked yet.");
} else {
List<VerificationStateInfo> infoHistory = relation.getVerificationStateInfo();
VerificationStateInfo info = infoHistory.get(infoHistory.size() - 1);
vulnerabilityVerifications.get(vulnerabilityId).put(releaseId, info.getVerificationState());
vulnerabilityTooltips.get(vulnerabilityId).put(releaseId, formatedMessageForVul(infoHistory));
}
}
private void putVulnerabilityMetadatasInRequest(RenderRequest request, List<VulnerabilityDTO> vuls) {
Map<String, Map<String, String>> vulnerabilityTooltips = new HashMap<>();
Map<String, Map<String, VerificationState>> vulnerabilityVerifications = new HashMap<>();
Map<String, Integer> matchedByHistogram = new HashMap<>();
for (VulnerabilityDTO vulnerability : vuls) {
addToVulnerabilityVerifications(vulnerabilityVerifications, vulnerabilityTooltips, vulnerability);
addToMatchedByHistogram(matchedByHistogram, vulnerability);
}
long numberOfCorrectVuls = vuls.stream()
.filter(vul -> ! VerificationState.INCORRECT.equals(getVerificationState(vul)))
.map(vul -> vul.getExternalId())
.collect(Collectors.toSet())
.size();
request.setAttribute(NUMBER_OF_CHECKED_OR_UNCHECKED_VULNERABILITIES, numberOfCorrectVuls);
if (PermissionUtils.isAdmin(UserCacheHolder.getUserFromRequest(request))) {
long numberOfIncorrectVuls = vuls.stream()
.filter(v -> VerificationState.INCORRECT.equals(getVerificationState(v)))
.map(vul -> vul.getExternalId())
.collect(Collectors.toSet())
.size();
request.setAttribute(NUMBER_OF_INCORRECT_VULNERABILITIES, numberOfIncorrectVuls);
}
request.setAttribute(PortalConstants.VULNERABILITY_MATCHED_BY_HISTOGRAM, matchedByHistogram);
request.setAttribute(PortalConstants.VULNERABILITY_VERIFICATIONS,vulnerabilityVerifications);
request.setAttribute(PortalConstants.VULNERABILITY_VERIFICATION_TOOLTIPS,vulnerabilityTooltips);
}
private void setUsingDocs(RenderRequest request, String releaseId, User user, ComponentService.Iface client) throws TException {
if (releaseId != null) {
ProjectService.Iface projectClient = thriftClients.makeProjectClient();
Set<Project> usingProjects = projectClient.searchByReleaseId(releaseId, user);
request.setAttribute(USING_PROJECTS, CommonUtils.nullToEmptySet(usingProjects));
final Set<Component> usingComponentsForRelease = client.getUsingComponentsForRelease(releaseId);
request.setAttribute(USING_COMPONENTS, CommonUtils.nullToEmptySet(usingComponentsForRelease));
} else {
request.setAttribute(USING_PROJECTS, Collections.emptySet());
request.setAttribute(USING_COMPONENTS, Collections.emptySet());
}
}
private void addComponentBreadcrumb(RenderRequest request, RenderResponse response, Component component) {
PortletURL componentUrl = response.createRenderURL();
componentUrl.setParameter(PAGENAME, PAGENAME_DETAIL);
componentUrl.setParameter(COMPONENT_ID, component.getId());
addBreadcrumbEntry(request, printName(component), componentUrl);
}
private void addReleaseBreadcrumb(RenderRequest request, RenderResponse response, Release release) {
PortletURL releaseURL = response.createRenderURL();
releaseURL.setParameter(PAGENAME, PAGENAME_RELEASE_DETAIL);
releaseURL.setParameter(RELEASE_ID, release.getId());
addBreadcrumbEntry(request, printName(release), releaseURL);
}
private void prepareStandardView(RenderRequest request) throws IOException {
List<Component> componentList = getFilteredComponentList(request);
Set<String> vendorNames;
try {
vendorNames = thriftClients.makeVendorClient().getAllVendorNames();
} catch (TException e) {
log.error("Problem retrieving all the Vendor names", e);
vendorNames = Collections.emptySet();
}
List<String> componentTypeNames = Arrays.asList(ComponentType.values())
.stream()
.map(ThriftEnumUtils::enumToString)
.collect(Collectors.toList());
request.setAttribute(VENDOR_LIST, new ThriftJsonSerializer().toJson(vendorNames));
request.setAttribute(COMPONENT_LIST, componentList);
request.setAttribute(COMPONENT_TYPE_LIST, new ThriftJsonSerializer().toJson(componentTypeNames));
}
private List<Component> getFilteredComponentList(PortletRequest request) throws IOException {
List<Component> componentList;
Map<String, Set<String>> filterMap = new HashMap<>();
for (Component._Fields filteredField : componentFilteredFields) {
String parameter = request.getParameter(filteredField.toString());
if (!isNullOrEmpty(parameter) &&
!(filteredField.equals(Component._Fields.COMPONENT_TYPE) && parameter.equals(PortalConstants.NO_FILTER))) {
Set<String> values = CommonUtils.splitToSet(parameter);
if (filteredField.equals(Component._Fields.NAME)) {
values = values.stream().map(v -> v + "*").collect(Collectors.toSet());
}
filterMap.put(filteredField.getFieldName(), values);
}
request.setAttribute(filteredField.getFieldName(), nullToEmpty(parameter));
}
try {
final User user = UserCacheHolder.getUserFromRequest(request);
ComponentService.Iface componentClient = thriftClients.makeComponentClient();
if (filterMap.isEmpty()) {
componentList = componentClient.getComponentSummary(user);
} else {
componentList = componentClient.refineSearch(null, filterMap);
}
} catch (TException e) {
log.error("Could not search components in backend ", e);
componentList = Collections.emptyList();
}
return componentList;
}
//! Actions
@UsedAsLiferayAction
public void updateComponent(ActionRequest request, ActionResponse response) throws PortletException, IOException {
String id = request.getParameter(COMPONENT_ID);
final User user = UserCacheHolder.getUserFromRequest(request);
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
if (id != null) {
Component component = client.getComponentByIdForEdit(id, user);
ComponentPortletUtils.updateComponentFromRequest(request, component);
RequestStatus requestStatus = client.updateComponent(component, user);
setSessionMessage(request, requestStatus, "Component", "update", component.getName());
cleanUploadHistory(user.getEmail(),id);
response.setRenderParameter(PAGENAME, PAGENAME_DETAIL);
response.setRenderParameter(COMPONENT_ID, request.getParameter(COMPONENT_ID));
} else {
Component component = new Component();
ComponentPortletUtils.updateComponentFromRequest(request, component);
AddDocumentRequestSummary summary = client.addComponent(component, user);
AddDocumentRequestStatus status = summary.getRequestStatus();
switch(status){
case SUCCESS:
String successMsg = "Component " + component.getName() + " added successfully";
SessionMessages.add(request, "request_processed", successMsg);
response.setRenderParameter(COMPONENT_ID, summary.getId());
response.setRenderParameter(PAGENAME, PAGENAME_EDIT);
break;
case DUPLICATE:
setSW360SessionError(request, ErrorMessages.COMPONENT_DUPLICATE);
response.setRenderParameter(PAGENAME, PAGENAME_EDIT);
prepareRequestForEditAfterDuplicateError(request, component);
break;
default:
setSW360SessionError(request, ErrorMessages.COMPONENT_NOT_ADDED);
response.setRenderParameter(PAGENAME, PAGENAME_VIEW);
}
}
} catch (TException e) {
log.error("Error fetching component from backend!", e);
}
}
private void prepareRequestForEditAfterDuplicateError(ActionRequest request, Component component) throws TException {
request.setAttribute(COMPONENT, component);
setAttachmentsInRequest(request, component.getAttachments());
request.setAttribute(USING_PROJECTS, Collections.emptySet());
request.setAttribute(USING_COMPONENTS, Collections.emptySet());
}
@UsedAsLiferayAction
public void updateRelease(ActionRequest request, ActionResponse response) throws PortletException, IOException {
String id = request.getParameter(COMPONENT_ID);
final User user = UserCacheHolder.getUserFromRequest(request);
if (id != null) {
try {
ComponentService.Iface client = thriftClients.makeComponentClient();
Component component = client.getComponentById(id, user);
Release release;
String releaseId = request.getParameter(RELEASE_ID);
if (releaseId != null) {
release = client.getReleaseByIdForEdit(releaseId, user);
ComponentPortletUtils.updateReleaseFromRequest(request, release);
RequestStatus requestStatus = client.updateRelease(release, user);
setSessionMessage(request, requestStatus, "Release", "update", printName(release));
cleanUploadHistory(user.getEmail(),releaseId);
response.setRenderParameter(PAGENAME, PAGENAME_RELEASE_DETAIL);
response.setRenderParameter(COMPONENT_ID, request.getParameter(COMPONENT_ID));
response.setRenderParameter(RELEASE_ID, request.getParameter(RELEASE_ID));
} else {
release = new Release();
release.setComponentId(component.getId());
release.setClearingState(ClearingState.NEW_CLEARING);
ComponentPortletUtils.updateReleaseFromRequest(request, release);
AddDocumentRequestSummary summary = client.addRelease(release, user);
AddDocumentRequestStatus status = summary.getRequestStatus();
switch(status){
case SUCCESS:
response.setRenderParameter(RELEASE_ID, summary.getId());
String successMsg = "Release " + printName(release) + " added successfully";
SessionMessages.add(request, "request_processed", successMsg);
response.setRenderParameter(PAGENAME, PAGENAME_EDIT_RELEASE);
break;
case DUPLICATE:
setSW360SessionError(request, ErrorMessages.RELEASE_DUPLICATE);
response.setRenderParameter(PAGENAME, PAGENAME_EDIT_RELEASE);
prepareRequestForReleaseEditAfterDuplicateError(request, release);
break;
default:
setSW360SessionError(request, ErrorMessages.RELEASE_NOT_ADDED);
response.setRenderParameter(PAGENAME, PAGENAME_DETAIL);
}
response.setRenderParameter(COMPONENT_ID, request.getParameter(COMPONENT_ID));
}
} catch (TException e) {
log.error("Error fetching release from backend!", e);
}
}
}
private void prepareRequestForReleaseEditAfterDuplicateError(ActionRequest request, Release release) throws TException {
fillVendor(release);
request.setAttribute(RELEASE, release);
setAttachmentsInRequest(request, release.getAttachments());
putDirectlyLinkedReleaseRelationsInRequest(request, release.getReleaseIdToRelationship());
request.setAttribute(USING_PROJECTS, Collections.emptySet());
request.setAttribute(USING_COMPONENTS, Collections.emptySet());
}
private void fillVendor(Release release) throws TException {
VendorService.Iface client = thriftClients.makeVendorClient();
if(release.isSetVendorId()) {
Vendor vendor = client.getByID(release.getVendorId());
release.setVendor(vendor);
}
}
@UsedAsLiferayAction
public void deleteRelease(ActionRequest request, ActionResponse response) throws PortletException, IOException {
RequestStatus requestStatus = ComponentPortletUtils.deleteRelease(request, log);
String userEmail = UserCacheHolder.getUserFromRequest(request).getEmail();
String releaseId = request.getParameter(PortalConstants.RELEASE_ID);
deleteUnneededAttachments(userEmail, releaseId);
setSessionMessage(request, requestStatus, "Release", "delete");
response.setRenderParameter(PAGENAME, PAGENAME_DETAIL);
response.setRenderParameter(COMPONENT_ID, request.getParameter(COMPONENT_ID));
}
@UsedAsLiferayAction
public void deleteComponent(ActionRequest request, ActionResponse response) throws PortletException, IOException {
RequestStatus requestStatus = ComponentPortletUtils.deleteComponent(request, log);
String userEmail = UserCacheHolder.getUserFromRequest(request).getEmail();
String id = request.getParameter(PortalConstants.COMPONENT_ID);
deleteUnneededAttachments(userEmail, id);
setSessionMessage(request, requestStatus, "Component", "delete");
}
@UsedAsLiferayAction
public void applyFilters(ActionRequest request, ActionResponse response) throws PortletException, IOException {
for (Component._Fields componentFilteredField : componentFilteredFields) {
response.setRenderParameter(componentFilteredField.toString(), nullToEmpty(request.getParameter(componentFilteredField.toString())));
}
}
private void updateVulnerabilitiesRelease(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
String releaseId = request.getParameter(PortalConstants.RELEASE_ID);
CveSearchService.Iface cveClient = thriftClients.makeCvesearchClient();
try {
VulnerabilityUpdateStatus importStatus = cveClient.updateForRelease(releaseId);
JSONObject responseData = PortletUtils.importStatusToJSON(importStatus);
PrintWriter writer = response.getWriter();
writer.write(responseData.toString());
} catch (TException e){
log.error("Error updating CVEs for release in backend.", e);
}
}
private void updateVulnerabilitiesComponent(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
String componentId = request.getParameter(PortalConstants.COMPONENT_ID);
CveSearchService.Iface cveClient = thriftClients.makeCvesearchClient();
try {
VulnerabilityUpdateStatus importStatus = cveClient.updateForComponent(componentId);
JSONObject responseData = PortletUtils.importStatusToJSON(importStatus);
PrintWriter writer = response.getWriter();
writer.write(responseData.toString());
} catch (TException e) {
log.error("Error updating CVEs for component in backend.", e);
}
}
private void updateAllVulnerabilities(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
CveSearchService.Iface cveClient = thriftClients.makeCvesearchClient();
try {
VulnerabilityUpdateStatus importStatus = cveClient.fullUpdate();
JSONObject responseData = PortletUtils.importStatusToJSON(importStatus);
PrintWriter writer = response.getWriter();
writer.write(responseData.toString());
} catch (TException e) {
log.error("Error occured with full update of CVEs in backend.", e);
}
}
private void updateVulnerabilityVerification(ResourceRequest request, ResourceResponse response) throws IOException{
String releaseId = request.getParameter(PortalConstants.RELEASE_ID);
String vulnerabilityExternalId = request.getParameter(PortalConstants.VULNERABILITY_ID);
User user = UserCacheHolder.getUserFromRequest(request);
VulnerabilityService.Iface vulClient = thriftClients.makeVulnerabilityClient();
try {
Vulnerability dbVulnerability = vulClient.getVulnerabilityByExternalId(vulnerabilityExternalId, user);
ReleaseVulnerabilityRelation dbRelation = vulClient.getRelationByIds(releaseId, dbVulnerability.getId(), user);
ReleaseVulnerabilityRelation resultRelation = ComponentPortletUtils.updateReleaseVulnerabilityRelationFromRequest(dbRelation, request);
RequestStatus requestStatus = vulClient.updateReleaseVulnerabilityRelation(resultRelation, user);
JSONObject responseData = JSONFactoryUtil.createJSONObject();
responseData.put(PortalConstants.REQUEST_STATUS, requestStatus.toString());
responseData.put(PortalConstants.VULNERABILITY_ID, vulnerabilityExternalId);
PrintWriter writer = response.getWriter();
writer.write(responseData.toString());
} catch (TException e) {
log.error("Error updating vulnerability verification for release "+ releaseId +" in backend.", e);
}
}
}