Java tutorial
package org.apache.archiva.rest.services; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.archiva.admin.model.RepositoryAdminException; import org.apache.archiva.admin.model.beans.ManagedRepository; import org.apache.archiva.common.utils.VersionComparator; import org.apache.archiva.common.utils.VersionUtil; import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder; import org.apache.archiva.maven2.metadata.MavenMetadataReader; import org.apache.archiva.maven2.model.Artifact; import org.apache.archiva.maven2.model.TreeEntry; import org.apache.archiva.metadata.generic.GenericMetadataFacet; import org.apache.archiva.metadata.model.ArtifactMetadata; import org.apache.archiva.metadata.model.MetadataFacet; import org.apache.archiva.metadata.model.ProjectVersionMetadata; import org.apache.archiva.metadata.model.ProjectVersionReference; import org.apache.archiva.metadata.repository.MetadataRepository; import org.apache.archiva.metadata.repository.MetadataRepositoryException; import org.apache.archiva.metadata.repository.MetadataResolutionException; import org.apache.archiva.metadata.repository.MetadataResolver; import org.apache.archiva.metadata.repository.RepositorySession; import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator; import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet; import org.apache.archiva.model.ArchivaArtifact; import org.apache.archiva.model.ArchivaRepositoryMetadata; import org.apache.archiva.proxy.model.RepositoryProxyConnectors; import org.apache.archiva.redback.components.cache.Cache; import org.apache.archiva.repository.ManagedRepositoryContent; import org.apache.archiva.repository.RepositoryContentFactory; import org.apache.archiva.repository.RepositoryException; import org.apache.archiva.repository.RepositoryNotFoundException; import org.apache.archiva.repository.metadata.MetadataTools; import org.apache.archiva.rest.api.model.ArtifactContent; import org.apache.archiva.rest.api.model.ArtifactContentEntry; import org.apache.archiva.rest.api.model.BrowseResult; import org.apache.archiva.rest.api.model.BrowseResultEntry; import org.apache.archiva.rest.api.model.Entry; import org.apache.archiva.rest.api.model.MetadataAddRequest; import org.apache.archiva.rest.api.model.VersionsList; import org.apache.archiva.rest.api.services.ArchivaRestServiceException; import org.apache.archiva.rest.api.services.BrowseService; import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator; import org.apache.archiva.security.ArchivaSecurityException; import org.apache.archiva.xml.XMLException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.springframework.stereotype.Service; import javax.inject.Inject; import javax.inject.Named; import javax.ws.rs.core.Response; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; /** * @author Olivier Lamy * @since 1.4-M3 */ @Service("browseService#rest") public class DefaultBrowseService extends AbstractRestService implements BrowseService { @Inject private DependencyTreeBuilder dependencyTreeBuilder; @Inject private RepositoryContentFactory repositoryContentFactory; @Inject @Named(value = "repositoryProxyConnectors#default") private RepositoryProxyConnectors connectors; @Inject @Named(value = "browse#versionMetadata") private Cache<String, ProjectVersionMetadata> versionMetadataCache; @Override public BrowseResult getRootGroups(String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); Set<String> namespaces = new LinkedHashSet<String>(); // TODO: this logic should be optional, particularly remembering we want to keep this code simple // it is located here to avoid the content repository implementation needing to do too much for what // is essentially presentation code Set<String> namespacesToCollapse = new LinkedHashSet<String>(); RepositorySession repositorySession = repositorySessionFactory.createSession(); try { MetadataResolver metadataResolver = repositorySession.getResolver(); for (String repoId : selectedRepos) { namespacesToCollapse.addAll(metadataResolver.resolveRootNamespaces(repositorySession, repoId)); } for (String n : namespacesToCollapse) { // TODO: check performance of this namespaces.add(collapseNamespaces(repositorySession, metadataResolver, selectedRepos, n)); } } catch (MetadataResolutionException e) { throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { repositorySession.close(); } List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>(namespaces.size()); for (String namespace : namespaces) { browseGroupResultEntries.add(new BrowseResultEntry(namespace, false)); } Collections.sort(browseGroupResultEntries); return new BrowseResult(browseGroupResultEntries); } @Override public BrowseResult browseGroupId(String groupId, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); Set<String> projects = new LinkedHashSet<>(); RepositorySession repositorySession = repositorySessionFactory.createSession(); Set<String> namespaces; try { MetadataResolver metadataResolver = repositorySession.getResolver(); Set<String> namespacesToCollapse = new LinkedHashSet<>(); for (String repoId : selectedRepos) { namespacesToCollapse.addAll(metadataResolver.resolveNamespaces(repositorySession, repoId, groupId)); projects.addAll(metadataResolver.resolveProjects(repositorySession, repoId, groupId)); } // TODO: this logic should be optional, particularly remembering we want to keep this code simple // it is located here to avoid the content repository implementation needing to do too much for what // is essentially presentation code namespaces = new LinkedHashSet<>(); for (String n : namespacesToCollapse) { // TODO: check performance of this namespaces.add( collapseNamespaces(repositorySession, metadataResolver, selectedRepos, groupId + "." + n)); } } catch (MetadataResolutionException e) { throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { repositorySession.close(); } List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>(namespaces.size() + projects.size()); for (String namespace : namespaces) { browseGroupResultEntries.add(new BrowseResultEntry(namespace, false).groupId(namespace)); } for (String project : projects) { browseGroupResultEntries .add(new BrowseResultEntry(groupId + '.' + project, true).groupId(groupId).artifactId(project)); } Collections.sort(browseGroupResultEntries); return new BrowseResult(browseGroupResultEntries); } @Override public VersionsList getVersionsList(String groupId, String artifactId, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); try { Collection<String> versions = getVersions(selectedRepos, groupId, artifactId); return new VersionsList(new ArrayList<>(versions)); } catch (MetadataResolutionException e) { throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } } private Collection<String> getVersions(List<String> selectedRepos, String groupId, String artifactId) throws MetadataResolutionException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { MetadataResolver metadataResolver = repositorySession.getResolver(); Set<String> versions = new LinkedHashSet<String>(); for (String repoId : selectedRepos) { Collection<String> projectVersions = metadataResolver.resolveProjectVersions(repositorySession, repoId, groupId, artifactId); versions.addAll(projectVersions); } List<String> sortedVersions = new ArrayList<>(versions); Collections.sort(sortedVersions, VersionComparator.getInstance()); return sortedVersions; } finally { repositorySession.close(); } } @Override public ProjectVersionMetadata getProjectMetadata(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); RepositorySession repositorySession = null; try { repositorySession = repositorySessionFactory.createSession(); MetadataResolver metadataResolver = repositorySession.getResolver(); ProjectVersionMetadata versionMetadata = null; for (String repoId : selectedRepos) { if (versionMetadata == null || versionMetadata.isIncomplete()) { try { ProjectVersionMetadata versionMetadataTmp = metadataResolver .resolveProjectVersion(repositorySession, repoId, groupId, artifactId, version); if (versionMetadata == null && versionMetadataTmp != null) { versionMetadata = versionMetadataTmp; } } catch (MetadataResolutionException e) { log.warn("Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}", groupId, artifactId, repoId, e.getMessage()); } } } return versionMetadata; } finally { if (repositorySession != null) { repositorySession.close(); } } } @Override public ProjectVersionMetadata getProjectVersionMetadata(String groupId, String artifactId, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); RepositorySession repositorySession = null; try { Collection<String> projectVersions = getVersions(selectedRepos, groupId, artifactId); repositorySession = repositorySessionFactory.createSession(); MetadataResolver metadataResolver = repositorySession.getResolver(); ProjectVersionMetadata sharedModel = new ProjectVersionMetadata(); MavenProjectFacet mavenFacet = new MavenProjectFacet(); mavenFacet.setGroupId(groupId); mavenFacet.setArtifactId(artifactId); sharedModel.addFacet(mavenFacet); boolean isFirstVersion = true; for (String version : projectVersions) { ProjectVersionMetadata versionMetadata = null; for (String repoId : selectedRepos) { if (versionMetadata == null || versionMetadata.isIncomplete()) { try { ProjectVersionMetadata projectVersionMetadataResolved = null; boolean useCache = !StringUtils.endsWith(version, VersionUtil.SNAPSHOT); String cacheKey = null; boolean cacheToUpdate = false; // FIXME a bit maven centric!!! // not a snapshot so get it from cache if (useCache) { cacheKey = repoId + groupId + artifactId + version; projectVersionMetadataResolved = versionMetadataCache.get(cacheKey); } if (useCache && projectVersionMetadataResolved != null) { versionMetadata = projectVersionMetadataResolved; } else { projectVersionMetadataResolved = metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId, version); versionMetadata = projectVersionMetadataResolved; cacheToUpdate = true; } if (useCache && cacheToUpdate) { versionMetadataCache.put(cacheKey, projectVersionMetadataResolved); } } catch (MetadataResolutionException e) { log.error("Skipping invalid metadata while compiling shared model for " + groupId + ":" + artifactId + " in repo " + repoId + ": " + e.getMessage()); } } } if (versionMetadata == null) { continue; } if (isFirstVersion) { sharedModel = versionMetadata; sharedModel.setId(null); } else { MavenProjectFacet versionMetadataMavenFacet = (MavenProjectFacet) versionMetadata .getFacet(MavenProjectFacet.FACET_ID); if (versionMetadataMavenFacet != null) { if (mavenFacet.getPackaging() != null // && !StringUtils.equalsIgnoreCase(mavenFacet.getPackaging(), versionMetadataMavenFacet.getPackaging())) { mavenFacet.setPackaging(null); } } if (StringUtils.isEmpty(sharedModel.getName()) // && !StringUtils.isEmpty(versionMetadata.getName())) { sharedModel.setName(versionMetadata.getName()); } if (sharedModel.getDescription() != null // && !StringUtils.equalsIgnoreCase(sharedModel.getDescription(), versionMetadata.getDescription())) { sharedModel.setDescription(StringUtils.isNotEmpty(versionMetadata.getDescription()) ? versionMetadata.getDescription() : ""); } if (sharedModel.getIssueManagement() != null // && versionMetadata.getIssueManagement() != null // && !StringUtils.equalsIgnoreCase(sharedModel.getIssueManagement().getUrl(), versionMetadata.getIssueManagement().getUrl())) { sharedModel.setIssueManagement(versionMetadata.getIssueManagement()); } if (sharedModel.getCiManagement() != null // && versionMetadata.getCiManagement() != null // && !StringUtils.equalsIgnoreCase(sharedModel.getCiManagement().getUrl(), versionMetadata.getCiManagement().getUrl())) { sharedModel.setCiManagement(versionMetadata.getCiManagement()); } if (sharedModel.getOrganization() != null // && versionMetadata.getOrganization() != null // && !StringUtils.equalsIgnoreCase(sharedModel.getOrganization().getName(), versionMetadata.getOrganization().getName())) { sharedModel.setOrganization(versionMetadata.getOrganization()); } if (sharedModel.getUrl() != null // && !StringUtils.equalsIgnoreCase(sharedModel.getUrl(), versionMetadata.getUrl())) { sharedModel.setUrl(versionMetadata.getUrl()); } } isFirstVersion = false; } return sharedModel; } catch (MetadataResolutionException e) { throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { if (repositorySession != null) { repositorySession.close(); } } } @Override public List<TreeEntry> getTreeEntries(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); try { return dependencyTreeBuilder.buildDependencyTree(selectedRepos, groupId, artifactId, version); } catch (Exception e) { log.error(e.getMessage(), e); } return Collections.emptyList(); } @Override public List<ManagedRepository> getUserRepositories() throws ArchivaRestServiceException { try { return userRepositories.getAccessibleRepositories(getPrincipal()); } catch (ArchivaSecurityException e) { throw new ArchivaRestServiceException("repositories.read.observable.error", Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } } @Override public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException { try { return userRepositories.getManagableRepositories(getPrincipal()); } catch (ArchivaSecurityException e) { throw new ArchivaRestServiceException("repositories.read.managable.error", Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } } @Override public List<Artifact> getDependees(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { List<ProjectVersionReference> references = new ArrayList<>(); // TODO: what if we get duplicates across repositories? RepositorySession repositorySession = repositorySessionFactory.createSession(); try { MetadataResolver metadataResolver = repositorySession.getResolver(); for (String repoId : getObservableRepos()) { // TODO: what about if we want to see this irrespective of version? references.addAll(metadataResolver.resolveProjectReferences(repositorySession, repoId, groupId, artifactId, version)); } } catch (MetadataResolutionException e) { throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { repositorySession.close(); } List<Artifact> artifacts = new ArrayList<>(references.size()); for (ProjectVersionReference projectVersionReference : references) { artifacts.add(new Artifact(projectVersionReference.getNamespace(), projectVersionReference.getProjectId(), projectVersionReference.getProjectVersion())); } return artifacts; } @Override public List<Entry> getMetadatas(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { ProjectVersionMetadata projectVersionMetadata = getProjectMetadata(groupId, artifactId, version, repositoryId); if (projectVersionMetadata == null) { return Collections.emptyList(); } MetadataFacet metadataFacet = projectVersionMetadata.getFacet(GenericMetadataFacet.FACET_ID); if (metadataFacet == null) { return Collections.emptyList(); } Map<String, String> map = metadataFacet.toProperties(); List<Entry> entries = new ArrayList<>(map.size()); for (Map.Entry<String, String> entry : map.entrySet()) { entries.add(new Entry(entry.getKey(), entry.getValue())); } return entries; } @Override public Boolean addMetadata(String groupId, String artifactId, String version, String key, String value, String repositoryId) throws ArchivaRestServiceException { ProjectVersionMetadata projectVersionMetadata = getProjectMetadata(groupId, artifactId, version, repositoryId); if (projectVersionMetadata == null) { return Boolean.FALSE; } Map<String, String> properties = new HashMap<>(); MetadataFacet metadataFacet = projectVersionMetadata.getFacet(GenericMetadataFacet.FACET_ID); if (metadataFacet != null && metadataFacet.toProperties() != null) { properties.putAll(metadataFacet.toProperties()); } else { metadataFacet = new GenericMetadataFacet(); } properties.put(key, value); metadataFacet.fromProperties(properties); projectVersionMetadata.addFacet(metadataFacet); RepositorySession repositorySession = repositorySessionFactory.createSession(); try { MetadataRepository metadataRepository = repositorySession.getRepository(); metadataRepository.updateProjectVersion(repositoryId, groupId, artifactId, projectVersionMetadata); repositorySession.save(); } catch (MetadataRepositoryException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { repositorySession.close(); } return Boolean.TRUE; } @Override public Boolean deleteMetadata(String groupId, String artifactId, String version, String key, String repositoryId) throws ArchivaRestServiceException { ProjectVersionMetadata projectVersionMetadata = getProjectMetadata(groupId, artifactId, version, repositoryId); if (projectVersionMetadata == null) { return Boolean.FALSE; } GenericMetadataFacet metadataFacet = (GenericMetadataFacet) projectVersionMetadata .getFacet(GenericMetadataFacet.FACET_ID); if (metadataFacet != null && metadataFacet.toProperties() != null) { Map<String, String> properties = metadataFacet.toProperties(); properties.remove(key); metadataFacet.setAdditionalProperties(properties); } else { return Boolean.TRUE; } RepositorySession repositorySession = repositorySessionFactory.createSession(); try { MetadataRepository metadataRepository = repositorySession.getRepository(); metadataRepository.updateProjectVersion(repositoryId, groupId, artifactId, projectVersionMetadata); repositorySession.save(); } catch (MetadataRepositoryException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } finally { repositorySession.close(); } return Boolean.TRUE; } @Override public List<ArtifactContentEntry> getArtifactContentEntries(String groupId, String artifactId, String version, String classifier, String type, String path, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); try { for (String repoId : selectedRepos) { ManagedRepositoryContent managedRepositoryContent = repositoryContentFactory .getManagedRepositoryContent(repoId); ArchivaArtifact archivaArtifact = new ArchivaArtifact(groupId, artifactId, version, classifier, StringUtils.isEmpty(type) ? "jar" : type, repoId); File file = managedRepositoryContent.toFile(archivaArtifact); if (file.exists()) { return readFileEntries(file, path, repoId); } } } catch (IOException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } catch (RepositoryNotFoundException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } catch (RepositoryException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } return Collections.emptyList(); } @Override public List<Artifact> getArtifactDownloadInfos(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); List<Artifact> artifactDownloadInfos = new ArrayList<>(); try (RepositorySession session = repositorySessionFactory.createSession()) { MetadataResolver metadataResolver = session.getResolver(); for (String repoId : selectedRepos) { List<ArtifactMetadata> artifacts = new ArrayList<>( metadataResolver.resolveArtifacts(session, repoId, groupId, artifactId, version)); Collections.sort(artifacts, ArtifactMetadataVersionComparator.INSTANCE); if (artifacts != null && !artifacts.isEmpty()) { return buildArtifacts(artifacts, repoId); } } } catch (MetadataResolutionException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } return artifactDownloadInfos; } @Override public ArtifactContent getArtifactContentText(String groupId, String artifactId, String version, String classifier, String type, String path, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); try { for (String repoId : selectedRepos) { ManagedRepositoryContent managedRepositoryContent = repositoryContentFactory .getManagedRepositoryContent(repoId); ArchivaArtifact archivaArtifact = new ArchivaArtifact(groupId, artifactId, version, classifier, StringUtils.isEmpty(type) ? "jar" : type, repoId); File file = managedRepositoryContent.toFile(archivaArtifact); if (!file.exists()) { log.debug("file: {} not exists for repository: {} try next repository", file, repoId); continue; } if (StringUtils.isNotBlank(path)) { // zip entry of the path -> path must a real file entry of the archive JarFile jarFile = new JarFile(file); ZipEntry zipEntry = jarFile.getEntry(path); try (InputStream inputStream = jarFile.getInputStream(zipEntry)) { return new ArtifactContent(IOUtils.toString(inputStream), repoId); } finally { closeQuietly(jarFile); } } return new ArtifactContent(FileUtils.readFileToString(file), repoId); } } catch (IOException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } catch (RepositoryNotFoundException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } catch (RepositoryException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } log.debug("artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type); // 404 ? return new ArtifactContent(); } @Override public Boolean artifactAvailable(String groupId, String artifactId, String version, String classifier, String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getSelectedRepos(repositoryId); boolean snapshot = VersionUtil.isSnapshot(version); try { for (String repoId : selectedRepos) { ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository(repoId); if ((snapshot && !managedRepository.isSnapshots()) || (!snapshot && managedRepository.isSnapshots())) { continue; } ManagedRepositoryContent managedRepositoryContent = repositoryContentFactory .getManagedRepositoryContent(repoId); // FIXME default to jar which can be wrong for war zip etc.... ArchivaArtifact archivaArtifact = new ArchivaArtifact(groupId, artifactId, version, StringUtils.isEmpty(classifier) ? "" : classifier, "jar", repoId); File file = managedRepositoryContent.toFile(archivaArtifact); if (file != null && file.exists()) { return true; } // in case of SNAPSHOT we can have timestamped version locally ! if (StringUtils.endsWith(version, VersionUtil.SNAPSHOT)) { File metadataFile = new File(file.getParent(), MetadataTools.MAVEN_METADATA); if (metadataFile.exists()) { try { ArchivaRepositoryMetadata archivaRepositoryMetadata = MavenMetadataReader .read(metadataFile); int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber(); String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp(); // rebuild file name with timestamped version and build number String timeStampFileName = new StringBuilder(artifactId).append('-') // .append(StringUtils.remove(version, "-" + VersionUtil.SNAPSHOT)) // .append('-').append(timeStamp) // .append('-').append(Integer.toString(buildNumber)) // .append((StringUtils.isEmpty(classifier) ? "" : "-" + classifier)) // .append(".jar").toString(); File timeStampFile = new File(file.getParent(), timeStampFileName); log.debug("try to find timestamped snapshot version file: {}", timeStampFile.getPath()); if (timeStampFile.exists()) { return true; } } catch (XMLException e) { log.warn("skip fail to find timestamped snapshot file: {}", e.getMessage()); } } } String path = managedRepositoryContent.toPath(archivaArtifact); file = connectors.fetchFromProxies(managedRepositoryContent, path); if (file != null && file.exists()) { // download pom now String pomPath = StringUtils.substringBeforeLast(path, ".jar") + ".pom"; connectors.fetchFromProxies(managedRepositoryContent, pomPath); return true; } } } catch (RepositoryAdminException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } catch (RepositoryException e) { log.error(e.getMessage(), e); throw new ArchivaRestServiceException(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e); } return false; } @Override public Boolean artifactAvailable(String groupId, String artifactId, String version, String repositoryId) throws ArchivaRestServiceException { return artifactAvailable(groupId, artifactId, version, null, repositoryId); } @Override public List<Artifact> getArtifacts(String repositoryId) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts(repositoryId); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } @Override public List<Artifact> getArtifactsByProjectVersionMetadata(String key, String value, String repositoryId) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository() .getArtifactsByProjectVersionMetadata(key, value, repositoryId); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } @Override public List<Artifact> getArtifactsByMetadata(String key, String value, String repositoryId) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata(key, value, repositoryId); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } @Override public List<Artifact> getArtifactsByProperty(String key, String value, String repositoryId) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty(key, value, repositoryId); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } @Override public Boolean importMetadata(MetadataAddRequest metadataAddRequest, String repositoryId) throws ArchivaRestServiceException { boolean result = true; for (Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet()) { result = addMetadata(metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(), metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(), repositoryId); if (!result) { break; } } return result; } @Override public List<Artifact> searchArtifacts(String text, String repositoryId, Boolean exact) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().searchArtifacts(text, repositoryId, exact == null ? false : exact); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } @Override public List<Artifact> searchArtifacts(String key, String text, String repositoryId, Boolean exact) throws ArchivaRestServiceException { RepositorySession repositorySession = repositorySessionFactory.createSession(); try { List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().searchArtifacts(key, text, repositoryId, exact == null ? false : exact); return buildArtifacts(artifactMetadatas, repositoryId); } catch (MetadataRepositoryException e) { throw new ArchivaRestServiceException(e.getMessage(), e); } finally { repositorySession.close(); } } //--------------------------- // internals //--------------------------- private void closeQuietly(JarFile jarFile) { if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { log.warn("ignore error closing jarFile {}", jarFile.getName()); } } } protected List<ArtifactContentEntry> readFileEntries(File file, String filterPath, String repoId) throws IOException { Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>(); int filterDepth = StringUtils.countMatches(filterPath, "/"); /*if ( filterDepth == 0 ) { filterDepth = 1; }*/ JarFile jarFile = new JarFile(file); try { Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries(); while (jarEntryEnumeration.hasMoreElements()) { JarEntry currentEntry = jarEntryEnumeration.nextElement(); String cleanedEntryName = StringUtils.endsWith(currentEntry.getName(), "/") ? // StringUtils.substringBeforeLast(currentEntry.getName(), "/") : currentEntry.getName(); String entryRootPath = getRootPath(cleanedEntryName); int depth = StringUtils.countMatches(cleanedEntryName, "/"); if (StringUtils.isEmpty(filterPath) // && !artifactContentEntryMap.containsKey(entryRootPath) // && depth == filterDepth) { artifactContentEntryMap.put(entryRootPath, new ArtifactContentEntry(entryRootPath, !currentEntry.isDirectory(), depth, repoId)); } else { if (StringUtils.startsWith(cleanedEntryName, filterPath) // && (depth == filterDepth || (!currentEntry.isDirectory() && depth == filterDepth))) { artifactContentEntryMap.put(cleanedEntryName, new ArtifactContentEntry(cleanedEntryName, !currentEntry.isDirectory(), depth, repoId)); } } } if (StringUtils.isNotEmpty(filterPath)) { Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>(); for (Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet()) { filteredArtifactContentEntryMap.put(entry.getKey(), entry.getValue()); } List<ArtifactContentEntry> sorted = getSmallerDepthEntries(filteredArtifactContentEntryMap); if (sorted == null) { return Collections.emptyList(); } Collections.sort(sorted, ArtifactContentEntryComparator.INSTANCE); return sorted; } } finally { if (jarFile != null) { jarFile.close(); } } List<ArtifactContentEntry> sorted = new ArrayList<>(artifactContentEntryMap.values()); Collections.sort(sorted, ArtifactContentEntryComparator.INSTANCE); return sorted; } private List<ArtifactContentEntry> getSmallerDepthEntries(Map<String, ArtifactContentEntry> entries) { int smallestDepth = Integer.MAX_VALUE; Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>(); for (Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet()) { ArtifactContentEntry current = entry.getValue(); if (current.getDepth() < smallestDepth) { smallestDepth = current.getDepth(); } List<ArtifactContentEntry> currentList = perDepthList.get(current.getDepth()); if (currentList == null) { currentList = new ArrayList<>(); currentList.add(current); perDepthList.put(current.getDepth(), currentList); } else { currentList.add(current); } } return perDepthList.get(smallestDepth); } /** * @param path * @return org/apache -> org , org -> org */ private String getRootPath(String path) { if (StringUtils.contains(path, '/')) { return StringUtils.substringBefore(path, "/"); } return path; } private List<String> getSelectedRepos(String repositoryId) throws ArchivaRestServiceException { List<String> selectedRepos = getObservableRepos(); if (CollectionUtils.isEmpty(selectedRepos)) { return Collections.emptyList(); } if (StringUtils.isNotEmpty(repositoryId)) { // check user has karma on the repository if (!selectedRepos.contains(repositoryId)) { throw new ArchivaRestServiceException("browse.root.groups.repositoy.denied", Response.Status.FORBIDDEN.getStatusCode(), null); } selectedRepos = Collections.singletonList(repositoryId); } return selectedRepos; } private String collapseNamespaces(RepositorySession repositorySession, MetadataResolver metadataResolver, Collection<String> repoIds, String n) throws MetadataResolutionException { Set<String> subNamespaces = new LinkedHashSet<String>(); for (String repoId : repoIds) { subNamespaces.addAll(metadataResolver.resolveNamespaces(repositorySession, repoId, n)); } if (subNamespaces.size() != 1) { log.debug("{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces); return n; } else { for (String repoId : repoIds) { Collection<String> projects = metadataResolver.resolveProjects(repositorySession, repoId, n); if (projects != null && !projects.isEmpty()) { log.debug("{} is not collapsible as it has projects", n); return n; } } return collapseNamespaces(repositorySession, metadataResolver, repoIds, n + "." + subNamespaces.iterator().next()); } } public Cache getVersionMetadataCache() { return versionMetadataCache; } public void setVersionMetadataCache(Cache versionMetadataCache) { this.versionMetadataCache = versionMetadataCache; } }