1 package org.apache.archiva.rest.services;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.admin.model.beans.ManagedRepository;
22 import org.apache.archiva.common.utils.VersionComparator;
23 import org.apache.archiva.common.utils.VersionUtil;
24 import org.apache.archiva.repository.ManagedRepositoryContent;
25 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
26 import org.apache.archiva.repository.maven.dependency.tree.DependencyTreeBuilder;
27 import org.apache.archiva.maven2.model.Artifact;
28 import org.apache.archiva.maven2.model.TreeEntry;
29 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
30 import org.apache.archiva.metadata.model.ArtifactMetadata;
31 import org.apache.archiva.metadata.model.MetadataFacet;
32 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
33 import org.apache.archiva.metadata.model.ProjectVersionReference;
34 import org.apache.archiva.metadata.repository.*;
35 import org.apache.archiva.repository.maven.metadata.storage.ArtifactMetadataVersionComparator;
36 import org.apache.archiva.repository.maven.metadata.storage.MavenProjectFacet;
37 import org.apache.archiva.model.ArchivaRepositoryMetadata;
38 import org.apache.archiva.proxy.ProxyRegistry;
39 import org.apache.archiva.proxy.model.RepositoryProxyHandler;
40 import org.apache.archiva.components.cache.Cache;
41 import org.apache.archiva.repository.ReleaseScheme;
42 import org.apache.archiva.repository.RepositoryException;
43 import org.apache.archiva.repository.RepositoryNotFoundException;
44 import org.apache.archiva.repository.RepositoryRegistry;
45 import org.apache.archiva.repository.metadata.MetadataReader;
46 import org.apache.archiva.repository.metadata.base.MetadataTools;
47 import org.apache.archiva.repository.storage.fs.FsStorageUtil;
48 import org.apache.archiva.repository.storage.StorageAsset;
49 import org.apache.archiva.rest.api.model.*;
50 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
51 import org.apache.archiva.rest.api.services.BrowseService;
52 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
53 import org.apache.archiva.security.ArchivaSecurityException;
54 import org.apache.commons.collections4.CollectionUtils;
55 import org.apache.commons.io.IOUtils;
56 import org.apache.commons.lang3.StringUtils;
57 import org.springframework.stereotype.Service;
59 import javax.inject.Inject;
60 import javax.inject.Named;
61 import javax.ws.rs.core.Response;
62 import java.io.IOException;
63 import java.io.InputStream;
64 import java.nio.charset.Charset;
65 import java.nio.file.Files;
67 import java.util.jar.JarEntry;
68 import java.util.jar.JarFile;
69 import java.util.zip.ZipEntry;
72 * @author Olivier Lamy
75 @Service( "browseService#rest" )
76 public class DefaultBrowseService
77 extends AbstractRestService
78 implements BrowseService
81 private final Charset ARTIFACT_CONTENT_ENCODING=Charset.forName( "UTF-8" );
84 private DependencyTreeBuilder dependencyTreeBuilder;
87 ProxyRegistry proxyRegistry;
90 RepositoryRegistry repositoryRegistry;
93 @Named( value = "browse#versionMetadata" )
94 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
96 private ManagedRepositoryContent getManagedRepositoryContent( String id) throws RepositoryException
98 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
100 throw new RepositoryException( "Could not find repository "+id );
102 return repo.getContent();
106 public BrowseResult getRootGroups( String repositoryId )
107 throws ArchivaRestServiceException
109 List<String> selectedRepos = getSelectedRepos( repositoryId );
111 Set<String> namespaces = new LinkedHashSet<String>();
113 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
114 // it is located here to avoid the content repository implementation needing to do too much for what
115 // is essentially presentation code
116 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
117 RepositorySession repositorySession = null;
120 repositorySession = repositorySessionFactory.createSession();
122 catch ( MetadataRepositoryException e )
124 e.printStackTrace( );
128 MetadataResolver metadataResolver = repositorySession.getResolver();
130 for ( String repoId : selectedRepos )
132 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
134 for ( String n : namespacesToCollapse )
136 // TODO: check performance of this
137 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
140 catch ( MetadataResolutionException e )
142 throw new ArchivaRestServiceException( e.getMessage(),
143 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
147 repositorySession.close();
150 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
151 for ( String namespace : namespaces )
153 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
156 Collections.sort( browseGroupResultEntries );
157 return new BrowseResult( browseGroupResultEntries );
161 public BrowseResult browseGroupId( String groupId, String repositoryId )
162 throws ArchivaRestServiceException
164 List<String> selectedRepos = getSelectedRepos( repositoryId );
166 Set<String> projects = new LinkedHashSet<>();
168 RepositorySession repositorySession = null;
171 repositorySession = repositorySessionFactory.createSession();
173 catch ( MetadataRepositoryException e )
175 e.printStackTrace( );
177 Set<String> namespaces;
180 MetadataResolver metadataResolver = repositorySession.getResolver();
182 Set<String> namespacesToCollapse = new LinkedHashSet<>();
183 for ( String repoId : selectedRepos )
185 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
187 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
190 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
191 // it is located here to avoid the content repository implementation needing to do too much for what
192 // is essentially presentation code
193 namespaces = new LinkedHashSet<>();
194 for ( String n : namespacesToCollapse )
196 // TODO: check performance of this
198 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
201 catch ( MetadataResolutionException e )
203 throw new ArchivaRestServiceException( e.getMessage(),
204 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
208 repositorySession.close();
210 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
211 for ( String namespace : namespaces )
213 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
215 for ( String project : projects )
217 browseGroupResultEntries.add(
218 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
220 Collections.sort( browseGroupResultEntries );
221 return new BrowseResult( browseGroupResultEntries );
226 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
227 throws ArchivaRestServiceException
229 List<String> selectedRepos = getSelectedRepos( repositoryId );
233 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
234 return new VersionsList( new ArrayList<>( versions ) );
236 catch ( MetadataResolutionException e )
238 throw new ArchivaRestServiceException( e.getMessage(),
239 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
244 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
245 throws MetadataResolutionException
248 RepositorySession repositorySession = null;
251 repositorySession = repositorySessionFactory.createSession();
253 catch ( MetadataRepositoryException e )
255 e.printStackTrace( );
259 MetadataResolver metadataResolver = repositorySession.getResolver();
261 Set<String> versions = new LinkedHashSet<String>();
263 for ( String repoId : selectedRepos )
265 Collection<String> projectVersions =
266 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
267 versions.addAll( projectVersions );
270 List<String> sortedVersions = new ArrayList<>( versions );
272 Collections.sort( sortedVersions, VersionComparator.getInstance() );
274 return sortedVersions;
278 repositorySession.close();
283 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
284 String repositoryId )
285 throws ArchivaRestServiceException
287 List<String> selectedRepos = getSelectedRepos( repositoryId );
289 RepositorySession repositorySession = null;
292 repositorySession = repositorySessionFactory.createSession();
294 MetadataResolver metadataResolver = repositorySession.getResolver();
296 ProjectVersionMetadata versionMetadata = null;
297 for ( String repoId : selectedRepos )
299 if ( versionMetadata == null || versionMetadata.isIncomplete() )
303 ProjectVersionMetadata versionMetadataTmp =
304 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
307 if ( versionMetadata == null && versionMetadataTmp != null )
309 versionMetadata = versionMetadataTmp;
314 catch ( MetadataResolutionException e )
316 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
317 groupId, artifactId, repoId, e.getMessage() );
322 return versionMetadata;
323 } catch (MetadataRepositoryException e) {
324 throw new ArchivaRestServiceException(e.getMessage(), e);
327 if ( repositorySession != null )
329 repositorySession.close();
336 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
337 throws ArchivaRestServiceException
340 List<String> selectedRepos = getSelectedRepos( repositoryId );
342 RepositorySession repositorySession = null;
346 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
348 repositorySession = repositorySessionFactory.createSession();
350 MetadataResolver metadataResolver = repositorySession.getResolver();
352 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
354 MavenProjectFacet mavenFacet = new MavenProjectFacet();
355 mavenFacet.setGroupId( groupId );
356 mavenFacet.setArtifactId( artifactId );
357 sharedModel.addFacet( mavenFacet );
359 boolean isFirstVersion = true;
361 for ( String version : projectVersions )
363 ProjectVersionMetadata versionMetadata = null;
364 for ( String repoId : selectedRepos )
366 if ( versionMetadata == null || versionMetadata.isIncomplete() )
370 ProjectVersionMetadata projectVersionMetadataResolved = null;
371 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
372 String cacheKey = null;
373 boolean cacheToUpdate = false;
374 // FIXME a bit maven centric!!!
375 // not a snapshot so get it from cache
378 cacheKey = repoId + groupId + artifactId + version;
379 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
381 if ( useCache && projectVersionMetadataResolved != null )
383 versionMetadata = projectVersionMetadataResolved;
387 projectVersionMetadataResolved =
388 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
389 artifactId, version );
390 versionMetadata = projectVersionMetadataResolved;
391 cacheToUpdate = true;
394 if ( useCache && cacheToUpdate )
396 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
400 catch ( MetadataResolutionException e )
402 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
403 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
408 if ( versionMetadata == null )
413 if ( isFirstVersion )
415 sharedModel = versionMetadata;
416 sharedModel.setId( null );
420 MavenProjectFacet versionMetadataMavenFacet =
421 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
422 if ( versionMetadataMavenFacet != null )
424 if ( mavenFacet.getPackaging() != null //
425 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
426 versionMetadataMavenFacet.getPackaging() ) )
428 mavenFacet.setPackaging( null );
432 if ( StringUtils.isEmpty( sharedModel.getName() ) //
433 && !StringUtils.isEmpty( versionMetadata.getName() ) )
435 sharedModel.setName( versionMetadata.getName() );
438 if ( sharedModel.getDescription() != null //
439 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
440 versionMetadata.getDescription() ) )
442 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
443 ? versionMetadata.getDescription()
447 if ( sharedModel.getIssueManagement() != null //
448 && versionMetadata.getIssueManagement() != null //
449 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
450 versionMetadata.getIssueManagement().getUrl() ) )
452 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
455 if ( sharedModel.getCiManagement() != null //
456 && versionMetadata.getCiManagement() != null //
457 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
458 versionMetadata.getCiManagement().getUrl() ) )
460 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
463 if ( sharedModel.getOrganization() != null //
464 && versionMetadata.getOrganization() != null //
465 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
466 versionMetadata.getOrganization().getName() ) )
468 sharedModel.setOrganization( versionMetadata.getOrganization() );
471 if ( sharedModel.getUrl() != null //
472 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
474 sharedModel.setUrl( versionMetadata.getUrl() );
478 isFirstVersion = false;
482 catch (MetadataResolutionException | MetadataRepositoryException e )
484 throw new ArchivaRestServiceException( e.getMessage(),
485 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
489 if ( repositorySession != null )
491 repositorySession.close();
497 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
498 throws ArchivaRestServiceException
500 List<String> selectedRepos = getSelectedRepos( repositoryId );
504 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
506 catch ( Exception e )
508 log.error( e.getMessage(), e );
511 return Collections.emptyList();
515 public List<ManagedRepository> getUserRepositories()
516 throws ArchivaRestServiceException
520 return userRepositories.getAccessibleRepositories( getPrincipal() );
522 catch ( ArchivaSecurityException e )
524 throw new ArchivaRestServiceException( "repositories.read.observable.error",
525 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
530 public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
533 return userRepositories.getManagableRepositories( getPrincipal() );
535 catch ( ArchivaSecurityException e )
537 throw new ArchivaRestServiceException( "repositories.read.managable.error",
538 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
543 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
544 throws ArchivaRestServiceException
546 List<ProjectVersionReference> references = new ArrayList<>();
547 // TODO: what if we get duplicates across repositories?
548 RepositorySession repositorySession = null;
551 repositorySession = repositorySessionFactory.createSession();
553 catch ( MetadataRepositoryException e )
555 e.printStackTrace( );
559 MetadataResolver metadataResolver = repositorySession.getResolver();
560 for ( String repoId : getObservableRepos() )
562 // TODO: what about if we want to see this irrespective of version?
564 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
568 catch ( MetadataResolutionException e )
570 throw new ArchivaRestServiceException( e.getMessage(),
571 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
575 repositorySession.close();
578 List<Artifact> artifacts = new ArrayList<>( references.size() );
580 for ( ProjectVersionReference projectVersionReference : references )
582 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
583 projectVersionReference.getProjectVersion() ) );
589 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
590 throws ArchivaRestServiceException
592 ProjectVersionMetadata projectVersionMetadata =
593 getProjectMetadata( groupId, artifactId, version, repositoryId );
594 if ( projectVersionMetadata == null )
596 return Collections.emptyList();
598 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
600 if ( metadataFacet == null )
602 return Collections.emptyList();
604 Map<String, String> map = metadataFacet.toProperties();
605 List<Entry> entries = new ArrayList<>( map.size() );
607 for ( Map.Entry<String, String> entry : map.entrySet() )
609 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
616 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
617 String repositoryId )
618 throws ArchivaRestServiceException
620 ProjectVersionMetadata projectVersionMetadata =
621 getProjectMetadata( groupId, artifactId, version, repositoryId );
623 if ( projectVersionMetadata == null )
625 return Boolean.FALSE;
628 Map<String, String> properties = new HashMap<>();
630 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
632 if ( metadataFacet != null && metadataFacet.toProperties() != null )
634 properties.putAll( metadataFacet.toProperties() );
638 metadataFacet = new GenericMetadataFacet();
641 properties.put( key, value );
643 metadataFacet.fromProperties( properties );
645 projectVersionMetadata.addFacet( metadataFacet );
647 RepositorySession repositorySession = null;
650 repositorySession = repositorySessionFactory.createSession();
652 catch ( MetadataRepositoryException e )
654 e.printStackTrace( );
659 MetadataRepository metadataRepository = repositorySession.getRepository();
661 metadataRepository.updateProjectVersion(repositorySession , repositoryId, groupId, artifactId, projectVersionMetadata );
663 repositorySession.save();
665 catch (MetadataRepositoryException | MetadataSessionException e )
667 log.error( e.getMessage(), e );
668 throw new ArchivaRestServiceException( e.getMessage(),
669 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
673 repositorySession.close();
679 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
680 throws ArchivaRestServiceException
682 ProjectVersionMetadata projectVersionMetadata =
683 getProjectMetadata( groupId, artifactId, version, repositoryId );
685 if ( projectVersionMetadata == null )
687 return Boolean.FALSE;
690 GenericMetadataFacet metadataFacet =
691 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
693 if ( metadataFacet != null && metadataFacet.toProperties() != null )
695 Map<String, String> properties = metadataFacet.toProperties();
696 properties.remove( key );
697 metadataFacet.setAdditionalProperties( properties );
704 RepositorySession repositorySession = null;
707 repositorySession = repositorySessionFactory.createSession();
709 catch ( MetadataRepositoryException e )
711 e.printStackTrace( );
716 MetadataRepository metadataRepository = repositorySession.getRepository();
718 metadataRepository.updateProjectVersion(repositorySession , repositoryId, groupId, artifactId, projectVersionMetadata );
720 repositorySession.save();
722 catch (MetadataRepositoryException | MetadataSessionException e )
724 log.error( e.getMessage(), e );
725 throw new ArchivaRestServiceException( e.getMessage(),
726 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
730 repositorySession.close();
736 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
737 String classifier, String type, String path,
738 String repositoryId )
739 throws ArchivaRestServiceException
741 List<String> selectedRepos = getSelectedRepos( repositoryId );
744 for ( String repoId : selectedRepos )
747 ManagedRepositoryContent managedRepositoryContent =
748 getManagedRepositoryContent( repoId );
749 ArchivaItemSelector itemSelector = ArchivaItemSelector.builder( ).withNamespace( groupId )
750 .withProjectId( artifactId ).withVersion( version ).withClassifier( classifier )
751 .withType( StringUtils.isEmpty( type ) ? "jar" : type )
752 .withArtifactId( artifactId ).build();
753 org.apache.archiva.repository.content.Artifact archivaArtifact = managedRepositoryContent.getItem( itemSelector ).adapt( org.apache.archiva.repository.content.Artifact.class );
754 StorageAsset file = archivaArtifact.getAsset();
757 return readFileEntries( file, path, repoId );
761 catch ( IOException e )
763 log.error( e.getMessage(), e );
764 throw new ArchivaRestServiceException( e.getMessage(),
765 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
767 catch ( RepositoryNotFoundException e )
769 log.error( e.getMessage(), e );
770 throw new ArchivaRestServiceException( e.getMessage(),
771 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
773 catch ( RepositoryException e )
775 log.error( e.getMessage(), e );
776 throw new ArchivaRestServiceException( e.getMessage(),
777 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
779 return Collections.emptyList();
783 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
784 String repositoryId )
785 throws ArchivaRestServiceException
787 List<String> selectedRepos = getSelectedRepos( repositoryId );
789 List<Artifact> artifactDownloadInfos = new ArrayList<>();
791 try (RepositorySession session = repositorySessionFactory.createSession())
793 MetadataResolver metadataResolver = session.getResolver();
794 for ( String repoId : selectedRepos )
796 List<ArtifactMetadata> artifacts = new ArrayList<>(
797 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
798 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
799 if ( artifacts != null && !artifacts.isEmpty() )
801 return buildArtifacts( artifacts, repoId );
805 catch ( MetadataResolutionException e )
807 log.error( e.getMessage(), e );
808 throw new ArchivaRestServiceException( e.getMessage(),
809 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
811 catch ( MetadataRepositoryException e )
813 e.printStackTrace( );
816 return artifactDownloadInfos;
820 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
821 String type, String path, String repositoryId )
822 throws ArchivaRestServiceException
824 List<String> selectedRepos = getSelectedRepos( repositoryId );
827 for ( String repoId : selectedRepos )
830 ManagedRepositoryContent managedRepositoryContent = null;
833 managedRepositoryContent = getManagedRepositoryContent( repoId );
835 catch ( RepositoryException e )
837 log.error("No repository content found for "+repoId);
840 ArchivaItemSelector itemSelector = ArchivaItemSelector.builder( ).withNamespace( groupId )
841 .withProjectId( artifactId ).withVersion( version ).withClassifier( classifier )
842 .withType( StringUtils.isEmpty( type ) ? "jar" : type )
843 .withArtifactId( artifactId ).build();
844 org.apache.archiva.repository.content.Artifact archivaArtifact = managedRepositoryContent.getItem( itemSelector ).adapt( org.apache.archiva.repository.content.Artifact.class );
845 StorageAsset file = archivaArtifact.getAsset( );
846 if ( !file.exists() )
848 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
851 if ( StringUtils.isNotBlank( path ) )
853 // zip entry of the path -> path must a real file entry of the archive
854 FsStorageUtil.PathInformation pathInfo = FsStorageUtil.getAssetDataAsPath(file);
855 JarFile jarFile = new JarFile( pathInfo.getPath().toFile());
856 ZipEntry zipEntry = jarFile.getEntry( path );
857 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
859 return new ArtifactContent( IOUtils.toString( inputStream, ARTIFACT_CONTENT_ENCODING ), repoId );
863 closeQuietly( jarFile );
864 if (pathInfo.isTmpFile()) {
865 Files.deleteIfExists(pathInfo.getPath());
869 try(InputStream readStream = file.getReadStream()) {
870 return new ArtifactContent(IOUtils.toString(readStream, ARTIFACT_CONTENT_ENCODING), repoId);
874 catch ( IOException e )
876 log.error( e.getMessage(), e );
877 throw new ArchivaRestServiceException( e.getMessage(),
878 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
880 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
882 return new ArtifactContent();
886 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
887 String repositoryId )
888 throws ArchivaRestServiceException
890 List<String> selectedRepos = getSelectedRepos( repositoryId );
892 boolean snapshot = VersionUtil.isSnapshot( version );
896 for ( String repoId : selectedRepos )
899 org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repoId);
900 if (!proxyRegistry.hasHandler(managedRepo.getType())) {
901 throw new RepositoryException( "No proxy handler found for repository type "+managedRepo.getType());
903 RepositoryProxyHandler proxyHandler = proxyRegistry.getHandler(managedRepo.getType()).get(0);
904 if ( ( snapshot && !managedRepo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) ) || ( !snapshot
905 && managedRepo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) ) )
909 ManagedRepositoryContent managedRepositoryContent = getManagedRepositoryContent( repoId );
911 // FIXME default to jar which can be wrong for war zip etc....
912 ArchivaItemSelector itemSelector = ArchivaItemSelector.builder( ).withNamespace( groupId )
913 .withProjectId( artifactId ).withVersion( version ).withClassifier( StringUtils.isEmpty( classifier )
917 .withArtifactId( artifactId ).build();
918 org.apache.archiva.repository.content.Artifact archivaArtifact = managedRepositoryContent.getItem( itemSelector ).adapt( org.apache.archiva.repository.content.Artifact.class );
919 StorageAsset file = archivaArtifact.getAsset( );
921 if ( file != null && file.exists() )
926 // in case of SNAPSHOT we can have timestamped version locally !
927 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
929 StorageAsset metadataFile = file.getStorage().getAsset(file.getParent().getPath()+"/"+MetadataTools.MAVEN_METADATA );
930 if ( metadataFile.exists() )
932 MetadataReader metadataReader = repositoryRegistry.getMetadataReader( managedRepositoryContent.getRepository( ).getType( ) );
933 ArchivaRepositoryMetadata archivaRepositoryMetadata =
934 metadataReader.read( metadataFile );
935 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
936 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
937 // rebuild file name with timestamped version and build number
938 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
939 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
940 .append( '-' ).append( timeStamp ) //
941 .append( '-' ).append( Integer.toString( buildNumber ) ) //
942 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
943 .append( ".jar" ).toString();
945 StorageAsset timeStampFile = file.getStorage().getAsset(file.getParent().getPath() + "/" + timeStampFileName );
946 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
947 if ( timeStampFile.exists() )
954 String path = managedRepositoryContent.toPath( archivaArtifact );
956 file = proxyHandler.fetchFromProxies( managedRepositoryContent.getRepository(), path );
958 if ( file != null && file.exists() )
961 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
962 proxyHandler.fetchFromProxies( managedRepositoryContent.getRepository(), pomPath );
966 } catch ( RepositoryException e )
968 log.error( e.getMessage(), e );
969 throw new ArchivaRestServiceException( e.getMessage(),
970 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
977 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
978 throws ArchivaRestServiceException
980 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
984 public List<Artifact> getArtifacts( String repositoryId )
985 throws ArchivaRestServiceException
987 RepositorySession repositorySession = null;
990 repositorySession = repositorySessionFactory.createSession();
992 catch ( MetadataRepositoryException e )
994 e.printStackTrace( );
998 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts(repositorySession , repositoryId );
999 return buildArtifacts( artifactMetadatas, repositoryId );
1001 catch ( MetadataRepositoryException e )
1003 throw new ArchivaRestServiceException( e.getMessage(), e );
1007 repositorySession.close();
1012 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
1013 throws ArchivaRestServiceException
1015 RepositorySession repositorySession = null;
1018 repositorySession = repositorySessionFactory.createSession();
1020 catch ( MetadataRepositoryException e )
1022 e.printStackTrace( );
1026 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionFacet(repositorySession , key, value, repositoryId );
1027 return buildArtifacts( artifactMetadatas, repositoryId );
1029 catch ( MetadataRepositoryException e )
1031 throw new ArchivaRestServiceException( e.getMessage(), e );
1035 repositorySession.close();
1040 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
1041 throws ArchivaRestServiceException
1043 RepositorySession repositorySession = null;
1046 repositorySession = repositorySessionFactory.createSession();
1048 catch ( MetadataRepositoryException e )
1050 e.printStackTrace( );
1054 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByAttribute(repositorySession , key, value, repositoryId );
1055 return buildArtifacts( artifactMetadatas, repositoryId );
1057 catch ( MetadataRepositoryException e )
1059 throw new ArchivaRestServiceException( e.getMessage(), e );
1063 repositorySession.close();
1068 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
1069 throws ArchivaRestServiceException
1071 RepositorySession repositorySession = null;
1074 repositorySession = repositorySessionFactory.createSession();
1076 catch ( MetadataRepositoryException e )
1078 e.printStackTrace( );
1082 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionAttribute(repositorySession , key, value, repositoryId );
1083 return buildArtifacts( artifactMetadatas, repositoryId );
1085 catch ( MetadataRepositoryException e )
1087 throw new ArchivaRestServiceException( e.getMessage(), e );
1091 repositorySession.close();
1096 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1097 throws ArchivaRestServiceException
1099 boolean result = true;
1100 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1102 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1103 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1114 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1115 throws ArchivaRestServiceException
1117 try(RepositorySession repositorySession = repositorySessionFactory.createSession())
1119 List<ArtifactMetadata> artifactMetadatas =
1120 repositorySession.getRepository().searchArtifacts(repositorySession , repositoryId, text, exact == null ? false : exact );
1121 return buildArtifacts( artifactMetadatas, repositoryId );
1123 catch ( MetadataRepositoryException e )
1125 throw new ArchivaRestServiceException( e.getMessage(), e );
1130 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1131 throws ArchivaRestServiceException
1133 RepositorySession repositorySession = null;
1136 repositorySession = repositorySessionFactory.createSession();
1138 catch ( MetadataRepositoryException e )
1140 e.printStackTrace( );
1144 List<ArtifactMetadata> artifactMetadatas =
1145 repositorySession.getRepository().searchArtifacts(repositorySession , repositoryId, key, text, exact == null ? false : exact );
1146 return buildArtifacts( artifactMetadatas, repositoryId );
1148 catch ( MetadataRepositoryException e )
1150 throw new ArchivaRestServiceException( e.getMessage(), e );
1154 repositorySession.close();
1158 //---------------------------
1160 //---------------------------
1162 private void closeQuietly( JarFile jarFile )
1164 if ( jarFile != null )
1170 catch ( IOException e )
1172 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1177 protected List<ArtifactContentEntry> readFileEntries(final StorageAsset file, final String filterPath, final String repoId )
1180 String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
1181 StringUtils.substringAfter(filterPath, "/") : filterPath);
1182 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1183 int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
1184 if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
1188 FsStorageUtil.PathInformation pathInfo = FsStorageUtil.getAssetDataAsPath(file);
1189 JarFile jarFile = new JarFile(pathInfo.getPath().toFile());
1192 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1193 while ( jarEntryEnumeration.hasMoreElements() )
1195 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1196 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
1197 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1198 String entryRootPath = getRootPath( cleanedEntryName );
1199 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1200 if ( StringUtils.isEmpty( cleanedfilterPath ) //
1201 && !artifactContentEntryMap.containsKey( entryRootPath ) //
1202 && depth == filterDepth )
1205 artifactContentEntryMap.put( entryRootPath,
1206 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1211 if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath ) //
1212 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1214 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1215 !currentEntry.isDirectory(),
1221 if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
1223 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1225 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1227 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1230 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1231 if ( sorted == null )
1233 return Collections.emptyList();
1235 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1241 if ( jarFile != null )
1245 if (pathInfo.isTmpFile()) {
1246 Files.deleteIfExists(pathInfo.getPath());
1249 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1250 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1254 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1256 int smallestDepth = Integer.MAX_VALUE;
1257 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1258 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1261 ArtifactContentEntry current = entry.getValue();
1263 if ( current.getDepth() < smallestDepth )
1265 smallestDepth = current.getDepth();
1268 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1270 if ( currentList == null )
1272 currentList = new ArrayList<>();
1273 currentList.add( current );
1274 perDepthList.put( current.getDepth(), currentList );
1278 currentList.add( current );
1283 return perDepthList.get( smallestDepth );
1288 * @return org/apache -> org , org -> org
1290 private String getRootPath( String path )
1292 if ( StringUtils.contains( path, '/' ) )
1294 return StringUtils.substringBefore( path, "/" );
1299 private List<String> getSelectedRepos( String repositoryId )
1300 throws ArchivaRestServiceException
1303 List<String> selectedRepos = getObservableRepos();
1305 if ( CollectionUtils.isEmpty( selectedRepos ) )
1307 return Collections.emptyList();
1310 if ( StringUtils.isNotEmpty( repositoryId ) )
1312 // check user has karma on the repository
1313 if ( !selectedRepos.contains( repositoryId ) )
1315 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1316 Response.Status.FORBIDDEN.getStatusCode(), null );
1318 selectedRepos = Collections.singletonList( repositoryId );
1320 return selectedRepos;
1324 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1325 Collection<String> repoIds, String n )
1326 throws MetadataResolutionException
1328 Set<String> subNamespaces = new LinkedHashSet<String>();
1329 for ( String repoId : repoIds )
1331 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1333 if ( subNamespaces.size() != 1 )
1335 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1340 for ( String repoId : repoIds )
1342 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1343 if ( projects != null && !projects.isEmpty() )
1345 log.debug( "{} is not collapsible as it has projects", n );
1349 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1350 n + "." + subNamespaces.iterator().next() );
1354 public Cache<String, ProjectVersionMetadata> getVersionMetadataCache()
1356 return versionMetadataCache;
1359 public void setVersionMetadataCache( Cache<String, ProjectVersionMetadata> versionMetadataCache )
1361 this.versionMetadataCache = versionMetadataCache;