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.datahandler.db; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.FluentIterable; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; import com.siemens.sw360.components.summary.SummaryType; import com.siemens.sw360.datahandler.businessrules.ReleaseClearingStateSummaryComputer; import com.siemens.sw360.datahandler.common.CommonUtils; import com.siemens.sw360.datahandler.common.SW360Utils; import com.siemens.sw360.datahandler.couchdb.AttachmentConnector; import com.siemens.sw360.datahandler.couchdb.DatabaseConnector; import com.siemens.sw360.datahandler.entitlement.ComponentModerator; import com.siemens.sw360.datahandler.permissions.PermissionUtils; import com.siemens.sw360.datahandler.thrift.*; import com.siemens.sw360.datahandler.thrift.attachments.Attachment; import com.siemens.sw360.datahandler.thrift.attachments.AttachmentType; import com.siemens.sw360.datahandler.thrift.components.*; import com.siemens.sw360.datahandler.thrift.moderation.ModerationRequest; import com.siemens.sw360.datahandler.thrift.projects.Project; import com.siemens.sw360.datahandler.thrift.users.RequestedAction; import com.siemens.sw360.datahandler.thrift.users.User; import com.siemens.sw360.datahandler.thrift.vendors.Vendor; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.ektorp.DocumentOperationResult; import org.jetbrains.annotations.NotNull; import java.net.MalformedURLException; import java.util.*; import java.util.concurrent.TimeUnit; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.collect.Sets.newHashSet; import static com.siemens.sw360.datahandler.common.CommonUtils.nullToEmptySet; import static com.siemens.sw360.datahandler.common.Duration.durationOf; import static com.siemens.sw360.datahandler.common.SW360Assert.assertNotNull; import static com.siemens.sw360.datahandler.common.SW360Assert.fail; import static com.siemens.sw360.datahandler.permissions.PermissionUtils.makePermission; import static com.siemens.sw360.datahandler.thrift.ThriftUtils.copyFields; import static com.siemens.sw360.datahandler.thrift.ThriftUtils.immutableOfComponent; import static com.siemens.sw360.datahandler.thrift.ThriftValidate.*; /** * Class for accessing Component information from the database * * @author cedric.bodet@tngtech.com * @author Johannes.Najjar@tngtech.com */ public class ComponentDatabaseHandler { private static final Logger log = Logger.getLogger(ComponentDatabaseHandler.class); /** * Connection to the couchDB database */ private final ComponentRepository componentRepository; private final ReleaseRepository releaseRepository; private final VendorRepository vendorRepository; private final ProjectRepository projectRepository; private final AttachmentConnector attachments; /** * Access to moderation */ private final ComponentModerator moderator; public ComponentDatabaseHandler(String url, String dbName, String attachmentDbName, ComponentModerator moderator) throws MalformedURLException { DatabaseConnector db = new DatabaseConnector(url, dbName); // Create the repositories vendorRepository = new VendorRepository(db); releaseRepository = new ReleaseRepository(db, vendorRepository); componentRepository = new ComponentRepository(db, releaseRepository, vendorRepository); projectRepository = new ProjectRepository(db); // Create the moderator this.moderator = moderator; // Create the attachment connector attachments = new AttachmentConnector(url, attachmentDbName, durationOf(30, TimeUnit.SECONDS)); } public ComponentDatabaseHandler(String url, String dbName, String attachmentDbName) throws MalformedURLException { this(url, dbName, attachmentDbName, new ComponentModerator()); } public ComponentDatabaseHandler(String url, String dbName, String attachmentDbName, ThriftClients thriftClients) throws MalformedURLException { this(url, dbName, attachmentDbName, new ComponentModerator(thriftClients)); } ///////////////////// // SUMMARY GETTERS // ///////////////////// public List<Component> getComponentSummary(User user) { return componentRepository.getComponentSummary(user); } public List<Component> getComponentSummaryForExport() { return componentRepository.getSummaryForExport(); } public List<Component> getComponentDetailedSummaryForExport() { return componentRepository.getDetailedSummaryForExport(); } public List<Release> getReleaseSummary() { return releaseRepository.getReleaseSummary(); } public List<Component> getRecentComponents() { return componentRepository.getRecentComponents(); } public List<Release> getRecentReleases() { return releaseRepository.getRecentReleases(); } public List<Component> getSubscribedComponents(String user) { return componentRepository.getSubscribedComponents(user); } public List<Release> getSubscribedReleases(String email) { return releaseRepository.getSubscribedReleases(email); } public List<Release> getReleasesFromVendorId(String id, User user) throws TException { return releaseRepository.getReleasesFromVendorId(id, user); } public List<Release> getReleasesFromVendorIds(Set<String> ids) { return releaseRepository.getReleasesFromVendorIds(ids); } public List<Component> getMyComponents(String user) { //This call could be sped up, because we want the full documents Set<String> myComponentIds = componentRepository.getMyComponentIds(user); //! but in general this will be the much larger junk and so we keep it this way Set<String> myComponentIdsFromReleases = releaseRepository.getMyComponentIds(user); return componentRepository.makeSummary(SummaryType.SHORT, Sets.union(myComponentIds, myComponentIdsFromReleases)); } public List<Component> getSummaryForExport() { return componentRepository.getSummaryForExport(); } //////////////////////////// // GET INDIVIDUAL OBJECTS // //////////////////////////// public Component getComponent(String id, User user) throws SW360Exception { Component component = componentRepository.get(id); if (component == null) { throw fail("Could not fetch component from database! id=" + id); } // Convert Ids to release summary component.setReleases( releaseRepository.makeSummaryWithPermissions(SummaryType.SUMMARY, component.releaseIds, user)); component.unsetReleaseIds(); setMainLicenses(component); // Set permissions makePermission(component, user).fillPermissions(); return component; } public Release getRelease(String id, User user) throws SW360Exception { Release release = releaseRepository.get(id); if (release == null) { throw fail("Could not fetch release from database! id=" + id); } if (release.isSetVendorId()) { String vendorId = release.getVendorId(); if (!isNullOrEmpty(vendorId)) { release.setVendor(getVendor(vendorId)); } release.unsetVendorId(); } // Set permissions if (user != null) { makePermission(release, user).fillPermissions(); } return release; } private void setMainLicenses(Component component) { if (!component.isSetMainLicenseIds() && component.isSetReleases()) { Set<String> licenseIds = new HashSet<>(); for (Release release : component.getReleases()) { licenseIds.addAll(nullToEmptySet(release.getMainLicenseIds())); } component.setMainLicenseIds(licenseIds); } } //////////////////////////// // ADD INDIVIDUAL OBJECTS // //////////////////////////// /** * Add new release to the database */ public String addComponent(Component component, String user) throws SW360Exception { // Prepare the component prepareComponent(component); // Save creating user component.setCreatedBy(user); component.setCreatedOn(SW360Utils.getCreatedOn()); // Add the component to the database and return ID componentRepository.add(component); return component.getId(); } /** * Add a single new release to the database */ public String addRelease(Release release, String user) throws SW360Exception { // Prepare the release and get underlying component ID ThriftValidate.prepareRelease(release); String componentId = release.getComponentId(); // Ensure that component exists Component component = componentRepository.get(componentId); assertNotNull(component); // Save creating user release.setCreatedBy(user); release.setCreatedOn(SW360Utils.getCreatedOn()); // Add release to database releaseRepository.add(release); final String id = release.getId(); // Update the underlying component component.addToReleaseIds(id); if (!component.isSetLanguages()) { component.setLanguages(new HashSet<String>()); } if (!component.isSetOperatingSystems()) { component.setOperatingSystems(new HashSet<String>()); } if (!component.isSetVendorNames()) { component.setVendorNames(new HashSet<String>()); } if (!component.isSetMainLicenseIds()) { component.setMainLicenseIds(new HashSet<String>()); } updateReleaseDependentFieldsForComponent(component, release); componentRepository.update(component); return id; } private void resetReleaseDependentFields(Component component) { component.setLanguages(new HashSet<String>()); component.setOperatingSystems(new HashSet<String>()); component.setVendorNames(new HashSet<String>()); component.setMainLicenseIds(new HashSet<String>()); } public void updateReleaseDependentFieldsForComponent(Component component, Release release) { if (release != null && component != null) { if (!component.isSetLanguages()) { component.setLanguages(new HashSet<String>()); } component.languages.addAll(nullToEmptySet(release.languages)); if (!component.isSetOperatingSystems()) { component.setOperatingSystems(new HashSet<String>()); } component.operatingSystems.addAll(nullToEmptySet(release.operatingSystems)); if (!component.isSetVendorNames()) { component.setVendorNames(new HashSet<String>()); } if (release.vendor != null) component.vendorNames.add(release.vendor.getFullname()); else if (!isNullOrEmpty(release.vendorId)) { Vendor vendor = getVendor(release.vendorId); component.vendorNames.add(vendor.getFullname()); } if (!component.isSetMainLicenseIds()) component.setMainLicenseIds(new HashSet<String>()); if (release.isSetMainLicenseIds()) { component.getMainLicenseIds().addAll(release.getMainLicenseIds()); } } } private Vendor getVendor(String vendorId) { return vendorRepository.get(vendorId); } /////////////////////////////// // UPDATE INDIVIDUAL OBJECTS // /////////////////////////////// public RequestStatus updateComponent(Component component, User user) throws SW360Exception { // Prepare component for database prepareComponent(component); // Get actual document for members that should no change Component actual = componentRepository.get(component.getId()); assertNotNull(actual, "Could not find component to doBulk!"); if (makePermission(actual, user).isActionAllowed(RequestedAction.WRITE)) { // Nested releases and attachments should not be updated by this method if (actual.isSetReleaseIds()) component.setReleaseIds(actual.getReleaseIds()); component.unsetReleases(); copyFields(actual, component, immutableOfComponent()); // Update the database with the component componentRepository.update(component); } else { return moderator.updateComponent(component, user); } return RequestStatus.SUCCESS; } public RequestSummary updateComponents(Set<Component> components, User user) throws SW360Exception { return RepositoryUtils.doBulk(prepareComponents(components), user, componentRepository); } public RequestStatus updateRelease(Release release, User user, Iterable<Release._Fields> immutableFields) throws SW360Exception { // Prepare release for database prepareRelease(release); // Get actual document for members that should no change Release actual = releaseRepository.get(release.getId()); assertNotNull(actual, "Could not find release to update"); if (actual.equals(release)) { return RequestStatus.SUCCESS; } if (makePermission(actual, user).isActionAllowed(RequestedAction.WRITE)) { copyFields(actual, release, immutableFields); releaseRepository.update(release); updateReleaseDependentFieldsForComponentId(release.getComponentId()); } else { return moderator.updateRelease(release, user); } return RequestStatus.SUCCESS; } public RequestSummary updateReleases(Collection<Release> releases, User user) throws SW360Exception { List<Release> storedReleases = prepareReleases(releases); RequestSummary requestSummary = new RequestSummary(); if (PermissionUtils.isAdmin(user)) { // Prepare component for database final List<DocumentOperationResult> documentOperationResults = componentRepository .executeBulk(storedReleases); if (documentOperationResults.isEmpty()) { final List<Component> componentList = componentRepository .get(FluentIterable.from(storedReleases).transform(new Function<Release, String>() { @Override public String apply(Release input) { return input.getComponentId(); } }).toSet()); final Map<String, Component> componentsById = ThriftUtils.getIdMap(componentList); for (Release storedRelease : storedReleases) { final Component component = componentsById.get(storedRelease.getComponentId()); component.addToReleaseIds(storedRelease.getId()); updateReleaseDependentFieldsForComponent(component, storedRelease); } updateComponents(newHashSet(componentList), user); } requestSummary.setTotalElements(storedReleases.size()); requestSummary.setTotalAffectedElements(storedReleases.size() - documentOperationResults.size()); requestSummary.setRequestStatus(RequestStatus.SUCCESS); } else { requestSummary.setRequestStatus(RequestStatus.FAILURE); } return requestSummary; } public Component updateReleaseDependentFieldsForComponentId(String componentId) { Component component = componentRepository.get(componentId); recomputeReleaseDependentFields(component, null); componentRepository.update(component); return component; } public void recomputeReleaseDependentFields(Component component, String skipThisReleaseId) { resetReleaseDependentFields(component); List<Release> releases = releaseRepository.get(component.getReleaseIds()); for (Release containedRelease : releases) { if (containedRelease.getId().equals(skipThisReleaseId)) continue; updateReleaseDependentFieldsForComponent(component, containedRelease); } } /////////////////////////////// // DELETE INDIVIDUAL OBJECTS // /////////////////////////////// public RequestStatus deleteComponent(String id, User user) throws SW360Exception { Component component = componentRepository.get(id); assertNotNull(component); final Set<String> releaseIds = component.getReleaseIds(); if (checkIfInUse(releaseIds)) return RequestStatus.IN_USE; if (makePermission(component, user).isActionAllowed(RequestedAction.DELETE)) { for (Release release : releaseRepository.get(nullToEmptySet(component.releaseIds))) { component = removeReleaseAndCleanUp(release); } // Remove the component with attachments attachments.deleteAttachments(component.getAttachments()); componentRepository.remove(component); moderator.notifyModeratorOnDelete(id); return RequestStatus.SUCCESS; } else { return moderator.deleteComponent(component, user); } } public boolean checkIfInUseComponent(String componentId) { Component component = componentRepository.get(componentId); return checkIfInUse(component); } public boolean checkIfInUse(Component component) { return checkIfInUse(component.getReleaseIds()); } public boolean checkIfInUse(Set<String> releaseIds) { if (releaseIds != null && releaseIds.size() > 0) { final Set<Component> usingComponents = componentRepository.getUsingComponents(releaseIds); if (usingComponents.size() > 0) return true; final Set<Project> usingProjects = projectRepository.searchByReleaseId(releaseIds); if (usingProjects.size() > 0) return true; } return false; } public boolean checkIfInUse(String releaseId) { final Set<Component> usingComponents = componentRepository.getUsingComponents(releaseId); if (usingComponents.size() > 0) return true; final Set<Project> usingProjects = projectRepository.searchByReleaseId(releaseId); return (usingProjects.size() > 0); } private Component removeReleaseAndCleanUp(Release release) { attachments.deleteAttachments(release.getAttachments()); Component component = updateReleaseDependentFieldsForComponentId(release.getComponentId()); //TODO notify using projects!?? Or stop if there are any moderator.notifyModeratorOnDelete(release.getId()); releaseRepository.remove(release); return component; } public RequestStatus deleteRelease(String id, User user) throws SW360Exception { Release release = releaseRepository.get(id); assertNotNull(release); if (checkIfInUse(id)) return RequestStatus.IN_USE; if (makePermission(release, user).isActionAllowed(RequestedAction.DELETE)) { // Remove release id from component removeReleaseId(id, release.componentId); removeReleaseAndCleanUp(release); return RequestStatus.SUCCESS; } else { return moderator.deleteRelease(release, user); } } private void removeReleaseId(String releaseId, String componentId) throws SW360Exception { // Remove release id from component Component component = componentRepository.get(componentId); assertNotNull(component); recomputeReleaseDependentFields(component, releaseId); component.getReleaseIds().remove(releaseId); componentRepository.update(component); } ///////////////////// // HELPER SERVICES // ///////////////////// /** * Get a summary of release status for a given set of IDs */ public ReleaseClearingStateSummary getReleaseClearingStateSummary(Set<String> ids, String clearingTeam) { List<Release> releases = null; if (ids != null && ids.size() > 0) { releases = releaseRepository.get(ids); } return ReleaseClearingStateSummaryComputer.computeReleaseClearingStateSummary(releases, clearingTeam); } public List<ReleaseLink> getLinkedReleases(Map<String, ?> relations) { List<ReleaseLink> out = new ArrayList<>(); final List<Release> releases = releaseRepository.getAll(); final Map<String, Release> releaseMap = ThriftUtils.getIdMap(releases); Set<String> visitedIds = new HashSet<>(); int depth = 0; Map<String, ReleaseRelationship> addedReleaseRelationShips = iterateReleaseRelationShips(relations, out, releaseMap, visitedIds, depth); while (!addedReleaseRelationShips.isEmpty()) { addedReleaseRelationShips = iterateReleaseRelationShips(addedReleaseRelationShips, out, releaseMap, visitedIds, ++depth); } return out; } @NotNull private Map<String, ReleaseRelationship> iterateReleaseRelationShips(Map<String, ?> relations, List<ReleaseLink> out, Map<String, Release> releaseMap, Set<String> visitedIds, int depth) { Map<String, ReleaseRelationship> addedReleaseRelationShips = new HashMap<>(); for (Map.Entry<String, ?> entry : relations.entrySet()) { String id = entry.getKey(); if (visitedIds.add(id)) { Release release = releaseMap.get(id); if (release != null) { final ReleaseLink releaseLink = getReleaseLink(id, release); fillValueFieldInReleaseLink(entry, releaseLink); releaseLink.setDepth(depth); if (release.isSetReleaseIdToRelationship()) { addedReleaseRelationShips.putAll(release.getReleaseIdToRelationship()); } out.add(releaseLink); } else { log.error("Broken ReleaseLink in release with id: " + id + ", was not in DB"); } } } return addedReleaseRelationShips; } private void fillValueFieldInReleaseLink(Map.Entry<String, ?> entry, ReleaseLink releaseLink) { Object value = entry.getValue(); if (value instanceof String) { releaseLink.setComment((String) value); } else if (value instanceof ReleaseRelationship) { releaseLink.setReleaseRelationship((ReleaseRelationship) value); } } @NotNull public ReleaseLink getReleaseLink(String id, Release release) { String fullname = ""; if (!isNullOrEmpty(release.getVendorId())) { final Vendor vendor = vendorRepository.get(release.getVendorId()); fullname = vendor != null ? vendor.getFullname() : ""; } return new ReleaseLink(id, fullname, release.name, release.version); } public List<Release> searchReleaseByName(String name) { return releaseRepository.searchByName(name); } public List<Release> getReleases(Set<String> ids, User user) { return releaseRepository.makeSummary(SummaryType.SHORT, ids); } public List<Release> getFullReleases(Set<String> ids, User user) { return releaseRepository.makeSummary(SummaryType.SUMMARY, ids); } public List<Release> getReleasesWithPermissions(Set<String> ids, User user) { return releaseRepository.makeSummaryWithPermissions(SummaryType.SUMMARY, ids, user); } public RequestStatus subscribeComponent(String id, User user) throws SW360Exception { Component component = componentRepository.get(id); assertNotNull(component); component.addToSubscribers(user.getEmail()); componentRepository.update(component); return RequestStatus.SUCCESS; } public RequestStatus subscribeRelease(String id, User user) throws SW360Exception { Release release = releaseRepository.get(id); assertNotNull(release); release.addToSubscribers(user.getEmail()); releaseRepository.update(release); return RequestStatus.SUCCESS; } public RequestStatus unsubscribeComponent(String id, User user) throws SW360Exception { Component component = componentRepository.get(id); assertNotNull(component); Set<String> subscribers = component.getSubscribers(); String email = user.getEmail(); if (subscribers != null && email != null) { subscribers.remove(email); component.setSubscribers(subscribers); } componentRepository.update(component); return RequestStatus.SUCCESS; } public RequestStatus unsubscribeRelease(String id, User user) throws SW360Exception { Release release = releaseRepository.get(id); assertNotNull(release); Set<String> subscribers = release.getSubscribers(); String email = user.getEmail(); if (subscribers != null && email != null) { subscribers.remove(email); release.setSubscribers(subscribers); } releaseRepository.update(release); return RequestStatus.SUCCESS; } public Component getComponentForEdit(String id, User user) throws SW360Exception { List<ModerationRequest> moderationRequestsForDocumentId = moderator.getModerationRequestsForDocumentId(id); Component component; DocumentState documentState; if (moderationRequestsForDocumentId.isEmpty()) { component = getComponent(id, user); documentState = CommonUtils.getOriginalDocumentState(); } else { final String email = user.getEmail(); Optional<ModerationRequest> moderationRequestOptional = CommonUtils .getFirstModerationRequestOfUser(moderationRequestsForDocumentId, email); if (moderationRequestOptional.isPresent()) { ModerationRequest moderationRequest = moderationRequestOptional.get(); component = moderationRequest.getComponent(); documentState = CommonUtils.getModeratedDocumentState(moderationRequest); } else { component = getComponent(id, user); documentState = new DocumentState().setIsOriginalDocument(true) .setModerationState(moderationRequestsForDocumentId.get(0).getModerationState()); } } component.setPermissions(makePermission(component, user).getPermissionMap()); component.setDocumentState(documentState); return component; } public Release getReleaseForEdit(String id, User user) throws SW360Exception { List<ModerationRequest> moderationRequestsForDocumentId = moderator.getModerationRequestsForDocumentId(id); Release release; DocumentState documentState; if (moderationRequestsForDocumentId.isEmpty()) { release = getRelease(id, user); documentState = CommonUtils.getOriginalDocumentState(); } else { final String email = user.getEmail(); Optional<ModerationRequest> moderationRequestOptional = CommonUtils .getFirstModerationRequestOfUser(moderationRequestsForDocumentId, email); if (moderationRequestOptional.isPresent()) { ModerationRequest moderationRequest = moderationRequestOptional.get(); release = moderationRequest.getRelease(); documentState = CommonUtils.getModeratedDocumentState(moderationRequest); } else { release = getRelease(id, user); documentState = new DocumentState().setIsOriginalDocument(true) .setModerationState(moderationRequestsForDocumentId.get(0).getModerationState()); } } release.setPermissions(makePermission(release, user).getPermissionMap()); release.setDocumentState(documentState); return release; } public List<Component> searchComponentByNameForExport(String name) { return componentRepository.searchByNameForExport(name); } public Set<Component> getUsingComponents(String releaseId) { return componentRepository.getUsingComponents(releaseId); } public Set<Component> getUsingComponents(Set<String> releaseIds) { return componentRepository.getUsingComponents(releaseIds); } public Component getComponentForReportFromFossologyUploadId(String uploadId) { Component component = componentRepository.getComponentFromFossologyUploadId(uploadId); if (component != null) { if (component.isSetReleaseIds()) { // Convert Ids to release summary final Set<String> releaseIds = component.getReleaseIds(); final List<Release> releases = CommonUtils.nullToEmptyList(releaseRepository.get(releaseIds)); for (Release release : releases) { fillVendor(release); } component.setReleases(releases); component.unsetReleaseIds(); setMainLicenses(component); } } return component; } private void fillVendor(Release release) { if (release.isSetVendorId()) { final String vendorId = release.getVendorId(); if (!Strings.isNullOrEmpty(vendorId)) { final Vendor vendor = vendorRepository.get(vendorId); if (vendor != null) release.setVendor(vendor); } release.unsetVendorId(); } } public Set<String> getusedAttachmentContentIds() { return componentRepository.getUsedAttachmentContents(); } public Map<String, List<String>> getDuplicateComponents() { ListMultimap<String, String> componentIdentifierToComponentId = ArrayListMultimap.create(); for (Component component : componentRepository.getAll()) { componentIdentifierToComponentId.put(SW360Utils.printName(component), component.getId()); } return CommonUtils.getIdentifierToListOfDuplicates(componentIdentifierToComponentId); } public Map<String, List<String>> getDuplicateReleases() { ListMultimap<String, String> releaseIdentifierToReleaseId = ArrayListMultimap.create(); for (Release release : releaseRepository.getAll()) { releaseIdentifierToReleaseId.put(SW360Utils.printName(release), release.getId()); } return CommonUtils.getIdentifierToListOfDuplicates(releaseIdentifierToReleaseId); } public Set<Attachment> getSourceAttachments(String releaseId) throws SW360Exception { Release release = assertNotNull(releaseRepository.get(releaseId)); final Predicate<Attachment> isSourceAttachment = new Predicate<Attachment>() { @Override public boolean apply(Attachment input) { return (input != null) && input.getAttachmentType() == AttachmentType.SOURCE; } }; return FluentIterable.from(nullToEmptySet(release.getAttachments())).filter(isSourceAttachment).toSet(); } public Map<String, List<String>> getDuplicateReleaseSources() { ListMultimap<String, String> releaseIdentifierToReleaseId = ArrayListMultimap.create(); for (Release release : releaseRepository.getAll()) { if (release.isSetAttachments()) { for (Attachment attachment : release.getAttachments()) { if (attachment.getAttachmentType() == AttachmentType.SOURCE) releaseIdentifierToReleaseId.put(SW360Utils.printName(release), release.getId()); } } } return CommonUtils.getIdentifierToListOfDuplicates(releaseIdentifierToReleaseId); } }