Java tutorial
/* * Artifactory is a binaries repository manager. * Copyright (C) 2012 JFrog Ltd. * * Artifactory is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Artifactory 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Artifactory. If not, see <http://www.gnu.org/licenses/>. */ package org.artifactory.repo.service; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.*; import org.apache.commons.lang.StringUtils; import org.artifactory.api.repo.*; import org.artifactory.api.repo.exception.FolderExpectedException; import org.artifactory.api.repo.exception.ItemNotFoundRuntimeException; import org.artifactory.api.security.AuthorizationService; import org.artifactory.checksum.ChecksumInfo; import org.artifactory.checksum.ChecksumType; import org.artifactory.checksum.ChecksumsInfo; import org.artifactory.fs.FileInfo; import org.artifactory.fs.ItemInfo; import org.artifactory.md.Properties; import org.artifactory.mime.MavenNaming; import org.artifactory.repo.*; import org.artifactory.repo.remote.browse.RemoteItem; import org.artifactory.repo.virtual.VirtualRepo; import org.artifactory.sapi.common.RepositoryRuntimeException; import org.artifactory.storage.fs.service.PropertiesService; import org.artifactory.storage.fs.tree.ItemNode; import org.artifactory.storage.fs.tree.ItemTree; import org.artifactory.storage.fs.tree.TreeBrowsingCriteriaBuilder; import org.artifactory.util.PathUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; /** * @author Tomer Cohen */ @Service public class RepositoryBrowsingServiceImpl implements RepositoryBrowsingService { private static final Logger log = LoggerFactory.getLogger(RepositoryBrowsingServiceImpl.class); @Autowired private AuthorizationService authService; @Autowired private InternalRepositoryService repoService; @Autowired private PropertiesService propertiesService; @Override public BrowsableItem getLocalRepoBrowsableItem(RepoPath repoPath) { ItemInfo itemInfo = getItemInfo(repoPath); return (itemInfo != null) ? BrowsableItem.getItem(itemInfo) : null; } @Override public VirtualBrowsableItem getVirtualRepoBrowsableItem(RepoPath repoPath) { log.debug("getting new Virtual Repo '{}' Browsable Item", repoPath.getRepoKey()); VirtualRepoItem virtualRepoItem = getVirtualRepoItem(repoPath); if (virtualRepoItem != null) { ItemInfo itemInfo = virtualRepoItem.getItemInfo(); log.debug("new Virtual Repo Browsable Item ,name:'{}',created:'{}',lastModified:'{}',size:'{}', ", itemInfo.getName(), itemInfo.getCreated(), itemInfo.getLastModified(), itemInfo.isFolder() ? -1 : ((FileInfo) itemInfo).getSize()); return new VirtualBrowsableItem(itemInfo.getName(), itemInfo.isFolder(), itemInfo.getCreated(), itemInfo.getLastModified(), itemInfo.isFolder() ? -1 : ((FileInfo) itemInfo).getSize(), repoPath, virtualRepoItem.getRepoKeys()); } else { return null; } } private ItemInfo getItemInfo(RepoPath repoPath) { LocalRepo repo = repoService.localOrCachedRepositoryByKey(repoPath.getRepoKey()); if (repo == null) { log.trace("No local or cache repo found:'{}'", repoPath.getRepoKey()); throw new IllegalArgumentException("No local or cache repo found: " + repoPath.getRepoKey()); } if (repo.isBlackedOut()) { return null; } return repoService.getItemInfo(repoPath); } @Override @Nonnull public List<BaseBrowsableItem> getLocalRepoBrowsableChildren(BrowsableItemCriteria criteria) { return getLocalRepoBrowsableChildrenData(criteria, false, null); } @Nullable @Override public List<BaseBrowsableItem> getLocalRepoBrowsableChildren(@Nonnull BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult browsableItemAccept) { return getLocalRepoBrowsableChildrenData(criteria, updateRootNodesFilterFlag, browsableItemAccept); } private List<BaseBrowsableItem> getLocalRepoBrowsableChildrenData(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult browsableItemAccept) { RepoPath repoPath = criteria.getRepoPath(); LocalRepo repo = repoService.localOrCachedRepositoryByKey(repoPath.getRepoKey()); if (repo == null) { log.trace("No local or cache repo found:'{}'", repoPath.getRepoKey()); throw new IllegalArgumentException("No local or cache repo found: " + repoPath.getRepoKey()); } if (repo.isBlackedOut() || !repo.accepts(repoPath)) { return Lists.newArrayListWithCapacity(0); } ItemTree tree = new ItemTree(criteria.getRepoPath(), new TreeBrowsingCriteriaBuilder() .applyRepoIncludeExclude().applySecurity().cacheChildren(false).build()); ItemNode rootNode = tree.getRootNode(); if (rootNode == null) { log.trace("No local or cache repo found:'{}'", repoPath.getRepoKey()); throw new ItemNotFoundRuntimeException(repoPath); } if (!rootNode.isFolder()) { log.trace("repo '{}' root node is not folder", repoPath.getRepoKey()); throw new FolderExpectedException(repoPath); } List<ItemNode> children = getRootNodeChildren(updateRootNodesFilterFlag, browsableItemAccept, rootNode); if (children.isEmpty()) { return Lists.newArrayListWithCapacity(0); } List<BaseBrowsableItem> repoPathChildren = Lists.newArrayList(); for (ItemNode child : children) { //Check if we should return the child ItemInfo childItemInfo = child.getItemInfo(); BrowsableItem browsableItem = BrowsableItem.getItem(childItemInfo); if (child.isFolder()) { repoPathChildren.add(browsableItem); } else if (isPropertiesMatch(childItemInfo, criteria.getRequestProperties())) { // match props for files repoPathChildren.add(browsableItem); if (criteria.isIncludeChecksums()) { repoPathChildren.addAll(getBrowsableItemChecksumItems(repo, ((FileInfo) childItemInfo).getChecksumsInfo(), browsableItem)); } } } Collections.sort(repoPathChildren); return repoPathChildren; } /** * call get children with monitor Filter Acceptance if flag is active or base get children * @param updateRootNodesFilterFlag - if true keep flag from empty list due to * no access (canRead = false) return * @param rootNodesFilterResult - * @param rootNode * @return children nodes List or empty list with updated browsableItemAccept canRead flag when * updateRootNodesFilterFlag is active */ private List<ItemNode> getRootNodeChildren(boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult, ItemNode rootNode) { List<ItemNode> children; if (updateRootNodesFilterFlag) { children = rootNode.getChildren(updateRootNodesFilterFlag, rootNodesFilterResult); } else { children = rootNode.getChildren(); } return children; } private boolean canRead(RealRepo repo, RepoPath childRepoPath) { return authService.canRead(childRepoPath) && repo.accepts(childRepoPath); } private boolean isPropertiesMatch(ItemInfo itemInfo, Properties requestProps) { if (requestProps == null || requestProps.isEmpty()) { return true; } Properties nodeProps = propertiesService.getProperties(itemInfo.getRepoPath()); Properties.MatchResult result = nodeProps.matchQuery(requestProps); return !Properties.MatchResult.CONFLICT.equals(result); } @Override @Nonnull public List<BaseBrowsableItem> getRemoteRepoBrowsableChildren(BrowsableItemCriteria criteria) { return getRemoteRepoBrowsableChildrenData(criteria, false, null); } @Override @Nonnull public List<BaseBrowsableItem> getRemoteRepoBrowsableChildren(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { return getRemoteRepoBrowsableChildrenData(criteria, updateRootNodesFilterFlag, rootNodesFilterResult); } private List<BaseBrowsableItem> getRemoteRepoBrowsableChildrenData(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { RepoPath repoPath = criteria.getRepoPath(); String repoKey = repoPath.getRepoKey(); String relativePath = repoPath.getPath(); RemoteRepo repo = repoService.remoteRepositoryByKey(repoKey); if (repo == null) { log.trace("Remote repo not found:'{}'", repoKey); throw new IllegalArgumentException("Remote repo not found: " + repoKey); } log.debug("Getting Remote Repo '{}' Browsable Children", repoKey); // include remote resources based on the flag and the offline mode boolean includeRemoteResources = criteria.isIncludeRemoteResources() && repo.isListRemoteFolderItems() && repo.accepts(repoPath); // first get all the cached items List<BaseBrowsableItem> children = Lists.newArrayList(); boolean pathExistsInCache = false; if (repo.isStoreArtifactsLocally()) { try { BrowsableItemCriteria cacheCriteria = new BrowsableItemCriteria.Builder(criteria) .repoPath(InternalRepoPathFactory.create(repo.getLocalCacheRepo().getKey(), relativePath)) .build(); if (updateRootNodesFilterFlag) { children = getLocalRepoBrowsableChildren(cacheCriteria, updateRootNodesFilterFlag, rootNodesFilterResult); } else { children = getLocalRepoBrowsableChildren(cacheCriteria); } pathExistsInCache = true; } catch (ItemNotFoundRuntimeException e) { // this is legit only if we also want to add remote items if (!includeRemoteResources) { throw e; } log.trace("Local Repository Item Not Found", e); } } if (includeRemoteResources) { listRemoteBrowsableChildren(children, repo, relativePath, pathExistsInCache, updateRootNodesFilterFlag, rootNodesFilterResult); } Collections.sort(children); return children; } private void listRemoteBrowsableChildren(List<BaseBrowsableItem> children, RemoteRepo repo, String relativePath, boolean pathExistsInCache, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { RepoPath repoPath = repo.getRepoPath(relativePath); List<RemoteItem> remoteItems = repo.listRemoteResources(relativePath); // probably remote not found - return 404 only if current folder doesn't exist in the cache if (remoteItems.isEmpty() && !pathExistsInCache) { // no cache and remote failed - signal 404 log.trace("Couldn't find item:'{}'", repoPath); throw new ItemNotFoundRuntimeException("Couldn't find item: " + repoPath); } log.debug("Listing Remote Repo '{}' Browsable Items", repoPath.getRepoKey()); // filter already existing local items remoteItems = Lists .newArrayList(Iterables.filter(remoteItems, new RemoteOnlyBrowsableItemPredicate(children))); for (RemoteItem remoteItem : remoteItems) { // remove the remote repository base url String path = StringUtils.removeStart(remoteItem.getUrl(), removeBaseUrl(repo.getUrl())); RepoPath remoteRepoPath = InternalRepoPathFactory.create(repoPath.getRepoKey(), path, remoteItem.isDirectory()); RepoPath cacheRepoPath = InternalRepoPathFactory.cacheRepoPath(remoteRepoPath); if (canRead(repo, cacheRepoPath)) { RemoteBrowsableItem browsableItem = new RemoteBrowsableItem(remoteItem, remoteRepoPath); if (remoteItem.getEffectiveUrl() != null) { log.debug("Remote Browsable item effective URL", remoteItem.getEffectiveUrl()); browsableItem.setEffectiveUrl(remoteItem.getEffectiveUrl()); } children.add(browsableItem); } else if (updateRootNodesFilterFlag && !authService.canRead(cacheRepoPath)) { rootNodesFilterResult.setAllItemNodesCanRead(false); } } if (updateRootNodesFilterFlag && !children.isEmpty()) { rootNodesFilterResult.setAllItemNodesCanRead(true); } } private String removeBaseUrl(String originalUrl) { //If remote url ends with / it messes up the path builder, since we already add it below it's safe to remove String remoteUrl = PathUtils.trimTrailingSlashes(originalUrl); ArtifactoryStandardUrlResolver artifactoryStandardUrlResolver = new ArtifactoryStandardUrlResolver( remoteUrl); StringBuilder baseUrlBuilder = new StringBuilder(artifactoryStandardUrlResolver.getBaseUrl()).append("/") .append(artifactoryStandardUrlResolver.getRepoKey()); if (!remoteUrl.endsWith("/")) { baseUrlBuilder.append("/"); } return baseUrlBuilder.toString(); } @Override @Nonnull public List<BaseBrowsableItem> getVirtualRepoBrowsableChildren(BrowsableItemCriteria criteria) { return getVirtualRepoBrowsableChildrenData(criteria, false, null); } @Override @Nonnull public List<BaseBrowsableItem> getVirtualRepoBrowsableChildren(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { return getVirtualRepoBrowsableChildrenData(criteria, updateRootNodesFilterFlag, rootNodesFilterResult); } private List<BaseBrowsableItem> getVirtualRepoBrowsableChildrenData(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { RepoPath repoPath = criteria.getRepoPath(); String virtualRepoKey = repoPath.getRepoKey(); VirtualRepo virtualRepo = repoService.virtualRepositoryByKey(virtualRepoKey); if (virtualRepo == null) { log.trace("No virtual repo found:'{}'", virtualRepoKey); throw new IllegalArgumentException("No virtual repo found: " + virtualRepoKey); } log.debug("getting Virtual Repo '{}' Browsable Item ", virtualRepoKey); List<BaseBrowsableItem> candidateChildren = Lists.newArrayList(); List<VirtualRepo> searchableRepos = getSearchableRepos(virtualRepo, repoPath); Multimap<String, VirtualRepo> pathToVirtualRepos = HashMultimap.create(); // add children from all local repos getVirtualBrowsableItemFromLocalAndRemote(criteria, updateRootNodesFilterFlag, rootNodesFilterResult, candidateChildren, searchableRepos, pathToVirtualRepos); // only add the candidate that this virtual repository accepts via its include/exclude rules Map<String, BaseBrowsableItem> childrenToReturn = Maps.newHashMap(); for (BaseBrowsableItem child : candidateChildren) { String childRelativePath = child.getRelativePath(); if (virtualRepoAccepts(virtualRepo, child.getRepoPath())) { log.debug("Virtual Repo '{}' accepts child repo path '{}' ", virtualRepoKey, child.getRepoPath()); VirtualBrowsableItem virtualItem; if (childrenToReturn.containsKey(childRelativePath)) { virtualItem = (VirtualBrowsableItem) childrenToReturn.get(childRelativePath); if (!child.isRemote() && virtualItem.isRemote()) { virtualItem.setCreated(child.getCreated()); virtualItem.setLastModified(child.getLastModified()); virtualItem.setSize(child.getSize()); log.debug("Updating virtual Item '{}' created '{}' ,lastModified '{}' and size '{}'", virtualItem.getName(), child.getCreated(), child.getLastModified(), child.getSize()); } } else { // New Collection<VirtualRepo> virtualRepos = pathToVirtualRepos.get(childRelativePath); virtualItem = new VirtualBrowsableItem(child.getName(), child.isFolder(), child.getCreated(), child.getLastModified(), child.getSize(), InternalRepoPathFactory.create(virtualRepoKey, childRelativePath, child.isFolder()), Lists.newArrayList(getSearchableRepoKeys(virtualRepos))); log.debug("New virtual Item '{}' created '{}' ,lastModified '{}' and size '{}'", virtualItem.getName(), child.getCreated(), child.getLastModified(), child.getSize()); virtualItem.setRemote(true); // default to true childrenToReturn.put(childRelativePath, virtualItem); } virtualItem.setRemote(virtualItem.isRemote() && child.isRemote()); // remote if all are remote virtualItem.addRepoKey(child.getRepoKey()); } } return Lists.newArrayList(childrenToReturn.values()); } /** * get browsable children items from local repository and remote repository , if list return is empty due to no * permission to access nodes then BrowsableItemAccept will be update so a challenge could be send to UI * @param criteria browsing criteria * @param updateRootNodesFilterFlag - is require to update item list with permission to access flag * @param rootNodesFilterResult - object that hold list permission to access flag * @param candidateChildren - list of brows children * @param searchableRepos - repose to search * @param pathToVirtualRepos - path to virtual repo */ private void getVirtualBrowsableItemFromLocalAndRemote(BrowsableItemCriteria criteria, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult, List<BaseBrowsableItem> candidateChildren, List<VirtualRepo> searchableRepos, Multimap<String, VirtualRepo> pathToVirtualRepos) { StringBuilder canReadReposFlags = new StringBuilder(); List<ItemNotFoundRuntimeException> itemNotFoundOnLocalList = new ArrayList<>(); List<ItemNotFoundRuntimeException> itemNotFoundOnRemoteList = new ArrayList<>(); int localIndex = 0; int remoteIndex = 0; if (updateRootNodesFilterFlag) { for (VirtualRepo repo : searchableRepos) { RootNodesFilterResult localBrowsableItemAccept = new RootNodesFilterResult(); RootNodesFilterResult remoteBrowsableItemAccept = new RootNodesFilterResult(); try { addVirtualBrowsableItemsFromLocal(criteria, repo, candidateChildren, pathToVirtualRepos, updateRootNodesFilterFlag, localBrowsableItemAccept); if (!repo.getLocalRepositories().isEmpty()) { localIndex++; } } catch (ItemNotFoundRuntimeException e) { localIndex++; itemNotFoundOnLocalList.add(e); } try { addVirtualBrowsableItemsFromRemote(criteria, repo, candidateChildren, pathToVirtualRepos, updateRootNodesFilterFlag, remoteBrowsableItemAccept); if (!repo.getRemoteRepositories().isEmpty()) { remoteIndex++; } } catch (ItemNotFoundRuntimeException e) { remoteIndex++; itemNotFoundOnRemoteList.add(e); } updatefolderCanRead(canReadReposFlags, localBrowsableItemAccept, remoteBrowsableItemAccept); } if (canReadReposFlags.toString().indexOf("false") != -1 && candidateChildren.isEmpty()) { rootNodesFilterResult.setAllItemNodesCanRead(false); } } else { for (VirtualRepo repo : searchableRepos) { RootNodesFilterResult localBrowsableItemAccept = new RootNodesFilterResult(); RootNodesFilterResult remoteBrowsableItemAccept = new RootNodesFilterResult(); try { addVirtualBrowsableItemsFromLocal(criteria, repo, candidateChildren, pathToVirtualRepos, updateRootNodesFilterFlag, localBrowsableItemAccept); if (!repo.getLocalRepositories().isEmpty()) { localIndex++; } } catch (ItemNotFoundRuntimeException e) { localIndex++; itemNotFoundOnLocalList.add(e); } try { addVirtualBrowsableItemsFromRemote(criteria, repo, candidateChildren, pathToVirtualRepos, updateRootNodesFilterFlag, remoteBrowsableItemAccept); if (!repo.getRemoteRepositories().isEmpty()) { remoteIndex++; } } catch (ItemNotFoundRuntimeException e) { remoteIndex++; itemNotFoundOnRemoteList.add(e); } } } if (isItemNotFoundOnVirtualRepo(candidateChildren, itemNotFoundOnLocalList, itemNotFoundOnRemoteList, remoteIndex + localIndex)) { throw new ItemNotFoundRuntimeException("children items not found on all virtual repos"); } } private boolean isItemNotFoundOnVirtualRepo(List<BaseBrowsableItem> candidateChildren, List<ItemNotFoundRuntimeException> itemNotFoundOnLocalList, List<ItemNotFoundRuntimeException> itemNotFoundOnRemoteList, int totalVirtualIndex) { return candidateChildren.isEmpty() && ((itemNotFoundOnLocalList.size() + itemNotFoundOnRemoteList.size()) == totalVirtualIndex); } /** * update repo folder can read * @param canReadReposFlags - update true / false flag for each repo that can or can not read * @param localBrowsableItemAccept - hold can read flag for local * @param remoteBrowsableItemAccept - hold can read flag for remote */ private void updatefolderCanRead(StringBuilder canReadReposFlags, RootNodesFilterResult localBrowsableItemAccept, RootNodesFilterResult remoteBrowsableItemAccept) { if (hasAtLeastOneItemWithReadPermission(localBrowsableItemAccept, remoteBrowsableItemAccept)) { canReadReposFlags.append("true"); } else { canReadReposFlags.append("false"); } } private boolean hasAtLeastOneItemWithReadPermission(RootNodesFilterResult localBrowsableItemAccept, RootNodesFilterResult remoteBrowsableItemAccept) { return (localBrowsableItemAccept.isAllItemNodesCanRead() && remoteBrowsableItemAccept.isAllItemNodesCanRead()); } private void addVirtualBrowsableItemsFromLocal(BrowsableItemCriteria criteria, VirtualRepo repo, List<BaseBrowsableItem> candidateChildren, Multimap<String, VirtualRepo> pathToVirtualRepos, boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult) { String relativePath = criteria.getRepoPath().getPath(); List<LocalRepo> localRepositories = repo.getLocalRepositories(); List<ItemNotFoundRuntimeException> itemNotFoundRuntimeExceptionList = new ArrayList<>(); log.debug("adding Virtual Browsable Items From Local to virtual Repo:'{}'", repo); for (LocalRepo localRepo : localRepositories) { RepoPath path = InternalRepoPathFactory.create(localRepo.getKey(), relativePath, criteria.getRepoPath().isFolder()); try { BrowsableItemCriteria localCriteria = new BrowsableItemCriteria.Builder(criteria).repoPath(path) .build(); log.trace("Iterating Browsable childrens of Local Repo :'{}' and check Virtual Repo Accepts it", localRepo.getKey()); List<BaseBrowsableItem> localRepoBrowsableChildren = getLocalBaseBrowsableItems( updateRootNodesFilterFlag, rootNodesFilterResult, localCriteria); // go over all local repo browsable children, these have already been filtered according // to each local repo's rules, now all that is left is to check that the virtual repo that // the local repo belongs to accepts as well. for (BaseBrowsableItem localRepoBrowsableChild : localRepoBrowsableChildren) { if (virtualRepoAccepts(repo, localRepoBrowsableChild.getRepoPath())) { log.debug("virtual repo accept Local Repo browsable child '{}':'{}'", localRepo.getKey(), localRepoBrowsableChild.getName()); pathToVirtualRepos.put(localRepoBrowsableChild.getRelativePath(), repo); candidateChildren.add(localRepoBrowsableChild); } } } catch (ItemNotFoundRuntimeException e) { log.trace("Could not find local browsable children at '{}'", criteria + " " + e.getMessage()); // add item not found exception to list updateItemNotFoundRuntimeExceptionsList(itemNotFoundRuntimeExceptionList, e); } } if (isAllLocalRepoReturnItemNotFoundException(localRepositories, itemNotFoundRuntimeExceptionList)) { throw new ItemNotFoundRuntimeException("Could not find local browsable children"); } } /** * update item not foound exception list for local and remote * @param itemNotFoundRuntimeExceptionList - item not found excception list referance * @param e - item not found exception */ private void updateItemNotFoundRuntimeExceptionsList( List<ItemNotFoundRuntimeException> itemNotFoundRuntimeExceptionList, ItemNotFoundRuntimeException e) { itemNotFoundRuntimeExceptionList.add(e); } /** * check weather all local repositories return item not found exception * * @param localRepositories - local repositories list * @param itemNotFoundRuntimeExceptionList - item not found exception list * @return - true if all local repositories return item not found exception */ private boolean isAllLocalRepoReturnItemNotFoundException(List<LocalRepo> localRepositories, List<ItemNotFoundRuntimeException> itemNotFoundRuntimeExceptionList) { return !itemNotFoundRuntimeExceptionList.isEmpty() && itemNotFoundRuntimeExceptionList.size() == localRepositories.size(); } /** * call getLocalRepoBrowsableChildren with monitor emptyList acceptance Flag if true or * base getLocalRepoBrowsableChildren if not * @param updateRootNodesFilterFlag - monitor BaseBrowsableItem empty list due to missing read permission to Node * @param rootNodesFilterResult - Hold the missing read permission to Node flag if BaseBrowsableItem list is empty * @param localCriteria - criteria to find nodes * @return list of BaseBrowsableItem */ private List<BaseBrowsableItem> getLocalBaseBrowsableItems(boolean updateRootNodesFilterFlag, RootNodesFilterResult rootNodesFilterResult, BrowsableItemCriteria localCriteria) { List<BaseBrowsableItem> localRepoBrowsableChildren; if (updateRootNodesFilterFlag) { localRepoBrowsableChildren = getLocalRepoBrowsableChildren(localCriteria, true, rootNodesFilterResult); } else { localRepoBrowsableChildren = getLocalRepoBrowsableChildren(localCriteria); } return localRepoBrowsableChildren; } private void addVirtualBrowsableItemsFromRemote(BrowsableItemCriteria criteria, VirtualRepo repo, List<BaseBrowsableItem> candidateChildren, Multimap<String, VirtualRepo> pathToVirtualRepos, boolean isBrowsableItemsAccepted, RootNodesFilterResult browsableItemAccept) { List<RemoteRepo> remoteRepositories = repo.getRemoteRepositories(); // add children from all remote repos (and their caches) log.debug("adding Virtual Browsable Items From Remote to virtual Repo:'{}'", repo); List<ItemNotFoundRuntimeException> itemNotFoundRuntimeExceptionList = new ArrayList<>(); for (RemoteRepo remoteRepo : remoteRepositories) { RepoPath remoteRepoPath = InternalRepoPathFactory.create(remoteRepo.getKey(), criteria.getRepoPath().getPath(), criteria.getRepoPath().isFolder()); try { BrowsableItemCriteria remoteCriteria = new BrowsableItemCriteria.Builder(criteria) .repoPath(remoteRepoPath).build(); List<BaseBrowsableItem> remoteRepoBrowsableChildren; if (isBrowsableItemsAccepted) { remoteRepoBrowsableChildren = getRemoteRepoBrowsableChildren(remoteCriteria, true, browsableItemAccept); } else { remoteRepoBrowsableChildren = getRemoteRepoBrowsableChildren(remoteCriteria); } log.trace("Iterating Browsable childrens of Remote Repo :'{}' and check Virtual Repo Accepts it", remoteRepo.getKey()); for (BaseBrowsableItem remoteRepoBrowsableChild : remoteRepoBrowsableChildren) { if (virtualRepoAccepts(repo, remoteRepoBrowsableChild.getRepoPath())) { log.debug("virtual repo accept Remote Repo browsable child '{}':'{}'", remoteRepo.getKey(), remoteRepoBrowsableChild.getName()); pathToVirtualRepos.put(remoteRepoBrowsableChild.getRelativePath(), repo); candidateChildren.add(remoteRepoBrowsableChild); } } } catch (ItemNotFoundRuntimeException e) { log.trace("Could not find local browsable children at '{}'", criteria + " " + e.getMessage()); // add item not found exception to list updateItemNotFoundRuntimeExceptionsList(itemNotFoundRuntimeExceptionList, e); } } if (isAllRemoteRepoReturnItemNotFoundException(remoteRepositories, itemNotFoundRuntimeExceptionList)) { throw new ItemNotFoundRuntimeException("Could not find remote browsable children"); } } /** * check weather all local repositories return item not found exception * * @param localRepositories - local repositories list * @param itemNotFoundRuntimeExceptionList - item not found exception list * @return - true if all local repositories return item not found exception */ private boolean isAllRemoteRepoReturnItemNotFoundException(List<RemoteRepo> localRepositories, List<ItemNotFoundRuntimeException> itemNotFoundRuntimeExceptionList) { return !itemNotFoundRuntimeExceptionList.isEmpty() && itemNotFoundRuntimeExceptionList.size() == localRepositories.size(); } private List<VirtualRepo> getSearchableRepos(VirtualRepo virtualRepo, RepoPath pathToCheck) { log.debug("getting searchable repositories of virtual repo '{}'", virtualRepo.getKey()); List<VirtualRepo> repos = Lists.newArrayList(); List<VirtualRepo> allVirtualRepos = virtualRepo.getResolvedVirtualRepos(); for (VirtualRepo repo : allVirtualRepos) { if (repo.accepts(pathToCheck)) { log.debug("repo '{}' accepts path '{}'", repo.getKey(), pathToCheck.getPath()); repos.add(repo); } } return repos; } private Collection<String> getSearchableRepoKeys(Collection<VirtualRepo> virtualRepos) { log.debug("getting searchable repositories of virtual repo keys "); return Collections2.transform(virtualRepos, new Function<VirtualRepo, String>() { @Override public String apply(@Nonnull VirtualRepo input) { log.trace("searchable repo key '{}'", input.getKey()); return input.getKey(); } }); } private boolean virtualRepoAccepts(VirtualRepo virtualRepo, RepoPath repoPath) { String path = repoPath.getPath(); if (repoPath.isFolder()) { path += "/"; } //If the path is not accepted, return immediately if (!virtualRepo.accepts(repoPath)) { log.debug("Virtual repo '{}' did not accept path '{}'", virtualRepo, repoPath); return false; } if (path.contains(MavenNaming.NEXUS_INDEX_DIR) || MavenNaming.isIndex(path)) { log.debug("Path '{}' is not an index", path); return false; } return true; } @Override public VirtualRepoItem getVirtualRepoItem(RepoPath repoPath) { VirtualRepo virtualRepo = repoService.virtualRepositoryByKey(repoPath.getRepoKey()); if (virtualRepo == null) { log.trace("Repository '{}' does not exists!", repoPath.getRepoKey()); throw new IllegalArgumentException("Repository " + repoPath.getRepoKey() + " does not exists!"); } log.debug("getting virtual Repo '{}' item", repoPath.getRepoKey()); VirtualRepoItem repoItem = virtualRepo.getVirtualRepoItem(repoPath); if (repoItem == null) { return null; } //Security - check that we can return the child Iterator<String> repoKeysIterator = repoItem.getRepoKeys().iterator(); while (repoKeysIterator.hasNext()) { String realRepoKey = repoKeysIterator.next(); RepoPath realRepoPath = InternalRepoPathFactory.create(realRepoKey, repoPath.getPath()); boolean canRead = authService.canRead(realRepoPath); if (!canRead) { log.trace("removing repo '{}' item, not have read access permission", realRepoKey); //Don't bother with stuff that we do not have read access to repoKeysIterator.remove(); } } // return null if user doesn't have permissions for any of the real repo paths if (repoItem.getRepoKeys().isEmpty()) { log.trace("user doesn't have permissions for any of the real repo paths"); return null; } else { return repoItem; } } @Override public List<VirtualRepoItem> getVirtualRepoItems(RepoPath folderPath) { log.debug("getting Virtual Repo Items '{}'", folderPath.getRepoKey()); VirtualRepo virtualRepo = repoService.virtualRepositoryByKey(folderPath.getRepoKey()); if (virtualRepo == null) { log.trace("Repository '{}' does not exists!", folderPath.getRepoKey()); throw new RepositoryRuntimeException("Repository " + folderPath.getRepoKey() + " does not exists!"); } //Get a deep children view of the virtual repository (including contained virtual repos) Set<String> children = virtualRepo.getChildrenNamesDeeply(folderPath); List<VirtualRepoItem> result = new ArrayList<>(children.size()); for (String childName : children) { //Do not add or check hidden items RepoPath childPath = InternalRepoPathFactory.create(folderPath, childName); VirtualRepoItem virtualRepoItem = getVirtualRepoItem(childPath); log.debug("getting Virtual Repo Item for folder path '{}' and child '{}'", folderPath.getRepoKey(), childName); if (virtualRepoItem != null) { result.add(virtualRepoItem); } } return result; } /** * Returns local-repo browsable items of checksums for the given browsable item * * @param repo Browsed repo * @param checksumsInfo Item's checksum info * @param browsableItem Browsable item to create checksum items for @return Checksum browsable items */ private List<BrowsableItem> getBrowsableItemChecksumItems(LocalRepo repo, ChecksumsInfo checksumsInfo, BrowsableItem browsableItem) { log.debug("getting Local repo Browsable Checksum Items for LocalRepo '{}'", repo.getKey()); List<BrowsableItem> browsableChecksumItems = Lists.newArrayList(); Set<ChecksumInfo> checksums = checksumsInfo.getChecksums(); for (ChecksumType checksumType : ChecksumType.BASE_CHECKSUM_TYPES) { String checksumValue = repo.getChecksumPolicy().getChecksum(checksumType, checksums); if (org.apache.commons.lang.StringUtils.isNotBlank(checksumValue)) { BrowsableItem checksumItem = BrowsableItem.getChecksumItem(browsableItem, checksumType, checksumValue.getBytes(Charsets.UTF_8).length); log.debug("getting Local repo Browsable Checksum Item '{}':'{}'", repo.getKey(), checksumItem.getName()); RepoPath checksumItemRepoPath = checksumItem.getRepoPath(); if (authService.canRead(checksumItemRepoPath) && repo.accepts(checksumItemRepoPath)) { browsableChecksumItems.add(checksumItem); } } } return browsableChecksumItems; } /** * This predicate returns true if a given item, represented by URL, doesn't already exists in the local items. */ private static class RemoteOnlyBrowsableItemPredicate implements Predicate<RemoteItem> { private List<BaseBrowsableItem> localItems; private RemoteOnlyBrowsableItemPredicate(List<BaseBrowsableItem> localItems) { this.localItems = localItems; } @Override public boolean apply(@Nonnull RemoteItem input) { for (BaseBrowsableItem localItem : localItems) { if (localItem.getName().equals(input.getName())) { return false; } } return true; } } }