Java tutorial
/* * Copyright Siemens AG, 2013-2015. Part of the SW360 Portal Project. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License Version 2.0 as published by the * Free Software Foundation with classpath exception. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License version 2.0 for * more details. * * You should have received a copy of the GNU General Public License along with * this program (please see the COPYING file); if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package com.siemens.sw360.portal.portlets.moderation; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.liferay.portal.kernel.servlet.SessionMessages; import com.siemens.sw360.datahandler.common.CommonUtils; import com.siemens.sw360.datahandler.common.SW360Constants; import com.siemens.sw360.datahandler.common.SW360Utils; import com.siemens.sw360.datahandler.thrift.ModerationState; import com.siemens.sw360.datahandler.thrift.RequestStatus; import com.siemens.sw360.datahandler.thrift.attachments.Attachment; import com.siemens.sw360.datahandler.thrift.components.Component; import com.siemens.sw360.datahandler.thrift.components.ComponentService; import com.siemens.sw360.datahandler.thrift.components.Release; import com.siemens.sw360.datahandler.thrift.components.ReleaseLink; import com.siemens.sw360.datahandler.thrift.licenses.License; import com.siemens.sw360.datahandler.thrift.moderation.ModerationRequest; import com.siemens.sw360.datahandler.thrift.moderation.ModerationService; import com.siemens.sw360.datahandler.thrift.projects.Project; import com.siemens.sw360.datahandler.thrift.projects.ProjectLink; import com.siemens.sw360.datahandler.thrift.projects.ProjectRelationship; import com.siemens.sw360.datahandler.thrift.projects.ProjectService; import com.siemens.sw360.datahandler.thrift.users.User; import com.siemens.sw360.portal.common.PortalConstants; import com.siemens.sw360.portal.portlets.FossologyAwarePortlet; import com.siemens.sw360.portal.users.UserCacheHolder; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.jetbrains.annotations.NotNull; import javax.portlet.*; import java.io.IOException; import java.util.*; import static com.siemens.sw360.datahandler.common.CommonUtils.nullToEmptySet; import static com.siemens.sw360.portal.common.PortalConstants.*; /** * Moderation portlet implementation * * @author daniele.fognini@tngtech.com * @author johannes.najjar@tngtech.com */ public class ModerationPortlet extends FossologyAwarePortlet { private static final Logger log = Logger.getLogger(ModerationPortlet.class); @Override public void serveResource(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { String action = request.getParameter(PortalConstants.ACTION); if (isGenericAction(action)) { dealWithGenericAction(request, response, action); } } @Override public void doView(RenderRequest request, RenderResponse response) throws IOException, PortletException { if (PAGENAME_EDIT.equals(request.getParameter(PAGENAME))) { renderEditView(request, response); } else if (PAGENAME_ACTION.equals(request.getParameter(PAGENAME))) { renderActionView(request, response); } else { renderStandardView(request, response); } } private void renderActionView(RenderRequest request, RenderResponse response) throws IOException, PortletException { final User user = UserCacheHolder.getUserFromRequest(request); final String id = request.getParameter(MODERATION_ID); String sessionMessage; if (id != null) { try { ModerationService.Iface client = thriftClients.makeModerationClient(); ModerationRequest moderationRequest = client.getModerationRequestById(id); if (ACTION_CANCEL.equals(request.getParameter(ACTION))) { client.cancelInProgress(id); sessionMessage = "You have cancelled working on the previous moderation request."; } else if (ACTION_DECLINE.equals(request.getParameter(ACTION))) { client.refuseRequest(id); sessionMessage = "You have decline the previous moderation request"; } else if (ACTION_ACCEPT.equals(request.getParameter(ACTION))) { acceptModerationRequest(user, moderationRequest); moderationRequest.setModerationState(ModerationState.APPROVED); moderationRequest.setReviewer(user.getEmail()); client.updateModerationRequest(moderationRequest); sessionMessage = "You have postponed the previous moderation request."; } else if (ACTION_POSTPONE.equals(request.getParameter(ACTION))) { // keep me assigned but do it later... so nothing to be done here sessionMessage = "You have postponed the previous moderation request."; } else if (ACTION_REMOVEME.equals(request.getParameter(ACTION))) { client.removeUserFromAssignees(id, user); sessionMessage = "You have removed yourself from the moderators of the previous moderation request."; } else { throw new PortletException("Unknown action"); } //! Actions are processed now we go and render the next one renderNextModeration(request, response, user, sessionMessage, client, moderationRequest); } catch (TException e) { log.error("Error in Moderation ", e); } } } private void acceptModerationRequest(User user, ModerationRequest moderationRequest) throws TException { switch (moderationRequest.getDocumentType()) { case COMPONENT: { ComponentService.Iface componentClient = thriftClients.makeComponentClient(); if (moderationRequest.isRequestDocumentDelete()) { componentClient.deleteComponent(moderationRequest.getDocumentId(), user); } else { componentClient.updateComponent(moderationRequest.getComponent(), user); } } break; case RELEASE: { ComponentService.Iface componentClient = thriftClients.makeComponentClient(); if (moderationRequest.isRequestDocumentDelete()) { componentClient.deleteRelease(moderationRequest.getDocumentId(), user); } else { componentClient.updateRelease(moderationRequest.getRelease(), user); } } break; case PROJECT: { ProjectService.Iface projectClient = thriftClients.makeProjectClient(); if (moderationRequest.isRequestDocumentDelete()) { projectClient.deleteProject(moderationRequest.getDocumentId(), user); } else { projectClient.updateProject(moderationRequest.getProject(), user); } } break; } } private void renderNextModeration(RenderRequest request, RenderResponse response, final User user, String sessionMessage, ModerationService.Iface client, ModerationRequest moderationRequest) throws IOException, PortletException, TException { if (ACTION_CANCEL.equals(request.getParameter(ACTION))) { SessionMessages.add(request, "request_processed", sessionMessage); renderStandardView(request, response); return; } List<ModerationRequest> requestsByModerator = client.getRequestsByModerator(user); ImmutableList<ModerationRequest> openModerationRequests = FluentIterable.from(requestsByModerator) .filter(new Predicate<ModerationRequest>() { @Override public boolean apply(ModerationRequest input) { return ModerationState.PENDING.equals(input.getModerationState()); } }).toList(); Collections.sort(openModerationRequests, compareByTimeStamp()); int nextIndex = openModerationRequests.indexOf(moderationRequest) + 1; if (nextIndex < openModerationRequests.size()) { sessionMessage += " You have assigned yourself to this moderation request."; SessionMessages.add(request, "request_processed", sessionMessage); renderEditViewForId(request, response, openModerationRequests.get(nextIndex).getId()); } else { FluentIterable<ModerationRequest> requestsInProgressAndAssignedToMe = FluentIterable .from(requestsByModerator).filter(new Predicate<ModerationRequest>() { @Override public boolean apply(ModerationRequest input) { return ModerationState.INPROGRESS.equals(input.getModerationState()) && user.getEmail().equals(input.getReviewer()); } }); if (requestsInProgressAndAssignedToMe.first().isPresent()) { sessionMessage += " You have returned to your first open request."; SessionMessages.add(request, "request_processed", sessionMessage); renderEditViewForId(request, response, Collections.min(requestsInProgressAndAssignedToMe.toList(), compareByTimeStamp()).getId()); } else { sessionMessage += " You have no open Requests."; SessionMessages.add(request, "request_processed", sessionMessage); renderStandardView(request, response); } } } @NotNull private Comparator<ModerationRequest> compareByTimeStamp() { return new Comparator<ModerationRequest>() { @Override public int compare(ModerationRequest o1, ModerationRequest o2) { return Long.compare(o1.getTimestamp(), o2.getTimestamp()); } }; } private void addModerationBreadcrumb(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest) { PortletURL baseUrl = response.createRenderURL(); baseUrl.setParameter(PAGENAME, PAGENAME_EDIT); baseUrl.setParameter(MODERATION_ID, moderationRequest.getId()); addBreadcrumbEntry(request, moderationRequest.getDocumentName(), baseUrl); } public void renderStandardView(RenderRequest request, RenderResponse response) throws IOException, PortletException { List<ModerationRequest> moderationRequests = null; try { ModerationService.Iface client = thriftClients.makeModerationClient(); User user = UserCacheHolder.getUserFromRequest(request); moderationRequests = client.getRequestsByModerator(user); } catch (TException e) { log.error("Could not fetch license summary from backend!", e); } request.setAttribute(MODERATION_REQUESTS, CommonUtils.nullToEmptyList(moderationRequests)); super.doView(request, response); } public void renderEditView(RenderRequest request, RenderResponse response) throws IOException, PortletException { String id = request.getParameter(MODERATION_ID); SessionMessages.add(request, "request_processed", "You have assigned yourself to this moderation request."); try { renderEditViewForId(request, response, id); } catch (TException e) { log.error("Thrift error", e); } } private void renderEditViewForId(RenderRequest request, RenderResponse response, String id) throws IOException, PortletException, TException { if (id != null) { ModerationRequest moderationRequest = null; User user = UserCacheHolder.getUserFromRequest(request); try { ModerationService.Iface client = thriftClients.makeModerationClient(); moderationRequest = client.getModerationRequestById(id); client.setInProgress(id, user); request.setAttribute(MODERATION_REQUEST, moderationRequest); addModerationBreadcrumb(request, response, moderationRequest); } catch (TException e) { log.error("Error fetching moderation details from backend", e); } if (moderationRequest != null) { switch (moderationRequest.getDocumentType()) { case COMPONENT: renderComponentModeration(request, response, moderationRequest, user); break; case RELEASE: renderReleaseModeration(request, response, moderationRequest, user); break; case PROJECT: renderProjectModeration(request, response, moderationRequest, user); break; } request.setAttribute(PortalConstants.MODERATION_REQUEST, moderationRequest); } } } public void renderComponentModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); Boolean is_used = false; Component actual_component = null; try { ComponentService.Iface client = thriftClients.makeComponentClient(); actual_component = client.getComponentById(moderationRequest.getDocumentId(), user); is_used = client.componentIsUsed(actual_component.getId()); } catch (TException e) { log.error("Could not retrieve component", e); } if (actual_component == null) { renderNextModeration(request, response, user, "Ingored unretrievable target", thriftClients.makeModerationClient(), moderationRequest); return; } if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) return; prepareComponent(request, user, actual_component, moderationRequest); request.setAttribute(PortalConstants.ACTUAL_COMPONENT, actual_component); if (moderationRequest.isRequestDocumentDelete()) { include("/html/moderation/components/delete.jsp", request, response); } else { include("/html/moderation/components/merge.jsp", request, response); } } private void prepareComponent(RenderRequest request, User user, Component actualComponent, ModerationRequest moderationRequest) { List<Release> releases; releases = CommonUtils.nullToEmptyList(actualComponent.getReleases()); Set<String> releaseIds = SW360Utils.getReleaseIds(releases); final Component moderatedComponent = moderationRequest.getComponent(); setLicenseNames(user, actualComponent, moderatedComponent); Set<Project> usingProjects = null; if (releaseIds != null && releaseIds.size() > 0) { try { ProjectService.Iface projectClient = thriftClients.makeProjectClient(); usingProjects = projectClient.searchByReleaseIds(releaseIds, user); } catch (TException e) { log.error("Could not retrieve using projects", e); } } request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_COMPONENT); setAttachmentsInRequest(request, actualComponent.getAttachments()); request.setAttribute(USING_PROJECTS, nullToEmptySet(usingProjects)); } public void renderReleaseModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { Release actual_release = null; final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); Boolean is_used = false; try { ComponentService.Iface client = thriftClients.makeComponentClient(); actual_release = client.getReleaseById(moderationRequest.getDocumentId(), user); is_used = client.releaseIsUsed(actual_release.getId()); } catch (TException e) { log.error("Could not retrieve release", e); } if (actual_release == null) { renderNextModeration(request, response, user, "Ingored unretrievable target", thriftClients.makeModerationClient(), moderationRequest); return; } if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) return; prepareRelease(request, user, actual_release, moderationRequest); request.setAttribute(PortalConstants.ACTUAL_RELEASE, actual_release); if (requestDocumentDelete) { include("/html/moderation/releases/delete.jsp", request, response); } else { include("/html/moderation/releases/merge.jsp", request, response); } } private boolean refuseToDeleteUsedDocument(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user, boolean requestDocumentDelete, Boolean is_used) throws TException, IOException, PortletException { if (requestDocumentDelete && is_used) { ModerationService.Iface client = thriftClients.makeModerationClient(); client.refuseRequest(moderationRequest.getId()); renderNextModeration(request, response, user, "Ingored delete of used target", client, moderationRequest); return true; } return false; } private void prepareRelease(RenderRequest request, User user, Release actualRelease, ModerationRequest moderationRequest) { final Release moderatedRelease = moderationRequest.getRelease(); setLicenseNames(user, actualRelease, moderatedRelease); String actualReleaseId = actualRelease.getId(); request.setAttribute(DOCUMENT_ID, actualReleaseId); request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_RELEASE); setAttachmentsInRequest(request, actualRelease.getAttachments()); try { ProjectService.Iface projectClient = thriftClients.makeProjectClient(); Set<Project> usingProjects = projectClient.searchByReleaseId(actualReleaseId, user); request.setAttribute(USING_PROJECTS, nullToEmptySet(usingProjects)); putLinkedReleaseRelationsInRequest(request, actualRelease.getReleaseIdToRelationship()); } catch (TException e) { log.error("Could not retrieve using projects", e); } try { request.setAttribute(COMPONENT, thriftClients.makeComponentClient().getComponentById(actualRelease.getComponentId(), user)); } catch (TException e) { log.error("Could not fetch component from Backend ", e); } } public void renderProjectModeration(RenderRequest request, RenderResponse response, ModerationRequest moderationRequest, User user) throws IOException, PortletException, TException { final boolean requestDocumentDelete = moderationRequest.isRequestDocumentDelete(); Boolean is_used = false; Project actual_project = null; try { ProjectService.Iface client = thriftClients.makeProjectClient(); actual_project = client.getProjectById(moderationRequest.getDocumentId(), user); is_used = client.projectIsUsed(actual_project.getId()); request.setAttribute(PortalConstants.ACTUAL_PROJECT, actual_project); } catch (TException e) { log.error("Could not retrieve project", e); } if (actual_project == null) { renderNextModeration(request, response, user, "Ingored unretrievable target", thriftClients.makeModerationClient(), moderationRequest); return; } if (refuseToDeleteUsedDocument(request, response, moderationRequest, user, requestDocumentDelete, is_used)) return; prepareProject(request, user, actual_project); if (moderationRequest.isRequestDocumentDelete()) { include("/html/moderation/projects/delete.jsp", request, response); } else { include("/html/moderation/projects/merge.jsp", request, response); } } private void prepareProject(RenderRequest request, User user, Project actual_project) { try { ProjectService.Iface client = thriftClients.makeProjectClient(); request.setAttribute(PortalConstants.PROJECT_LIST, getLinkedProjects(actual_project.getLinkedProjects())); putLinkedReleasesInRequest(request, actual_project.getReleaseIdToUsage()); Set<Project> usingProjects = client.searchLinkingProjects(actual_project.getId(), user); request.setAttribute(USING_PROJECTS, usingProjects); Map<Release, String> releaseStringMap = getReleaseStringMap(actual_project.getId(), user); request.setAttribute(PortalConstants.RELEASES_AND_PROJECTS, releaseStringMap); request.setAttribute(DOCUMENT_TYPE, SW360Constants.TYPE_PROJECT); setAttachmentsInRequest(request, actual_project.getAttachments()); } catch (TException e) { log.error("Error fetching project from backend!", e); } } private Map<Integer, Collection<ReleaseLink>> getLinkedReleases(Map<String, String> releaseIdToUsage) { return SW360Utils.getLinkedReleases(releaseIdToUsage, thriftClients, log); } private List<ProjectLink> getLinkedProjects(Map<String, ProjectRelationship> linkedProjects) { return SW360Utils.getLinkedProjects(linkedProjects, thriftClients, log); } private UnsupportedOperationException unsupportedActionException() { throw new UnsupportedOperationException("cannot call this action on the moderation portlet"); } private static void setLicenseNames(User user, Component actualComponent, Component moderatedComponent) { Set<String> licenseIds = new HashSet<>(); if (actualComponent.isSetMainLicenseIds()) { licenseIds.addAll(actualComponent.getMainLicenseIds()); } if (moderatedComponent.isSetMainLicenseIds()) { licenseIds.addAll(moderatedComponent.getMainLicenseIds()); } Map<String, License> idToLicense = SW360Utils.getStringLicenseMap(user, licenseIds); SW360Utils.setLicenseNames(actualComponent, idToLicense); SW360Utils.setLicenseNames(moderatedComponent, idToLicense); } private static void setLicenseNames(User user, Release actualRelease, Release moderatedRelease) { Set<String> licenseIds = new HashSet<>(); if (actualRelease.isSetMainLicenseIds()) { licenseIds.addAll(actualRelease.getMainLicenseIds()); } if (moderatedRelease.isSetMainLicenseIds()) { licenseIds.addAll(moderatedRelease.getMainLicenseIds()); } Map<String, License> idToLicense = SW360Utils.getStringLicenseMap(user, licenseIds); SW360Utils.setLicenseNames(actualRelease, idToLicense); SW360Utils.setLicenseNames(moderatedRelease, idToLicense); } @Override protected void dealWithFossologyAction(ResourceRequest request, ResourceResponse response, String action) throws IOException, PortletException { if (PortalConstants.FOSSOLOGY_GET_STATUS.equals(action)) { serveFossologyStatus(request, response); } else { throw unsupportedActionException(); } } @Override protected Attachment linkAttachment(String documentId, String documentType, User user, String attachmentId) { throw unsupportedActionException(); } @Override protected RequestStatus deleteAttachment(String documentId, String documentType, User user, String attachmentId) { throw unsupportedActionException(); } @Override protected Set<Attachment> getAttachments(String documentId, String documentType, User user) { throw unsupportedActionException(); } }