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.dependency.tree.maven2.DependencyTreeBuilder;
25 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
26 import org.apache.archiva.maven2.model.Artifact;
27 import org.apache.archiva.maven2.model.TreeEntry;
28 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
29 import org.apache.archiva.metadata.model.ArtifactMetadata;
30 import org.apache.archiva.metadata.model.MetadataFacet;
31 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
32 import org.apache.archiva.metadata.model.ProjectVersionReference;
33 import org.apache.archiva.metadata.repository.*;
34 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
35 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
36 import org.apache.archiva.model.ArchivaArtifact;
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.ManagedRepositoryContent;
42 import org.apache.archiva.repository.ReleaseScheme;
43 import org.apache.archiva.repository.RepositoryException;
44 import org.apache.archiva.repository.RepositoryNotFoundException;
45 import org.apache.archiva.repository.metadata.base.MetadataTools;
46 import org.apache.archiva.repository.storage.StorageAsset;
47 import org.apache.archiva.repository.storage.StorageUtil;
48 import org.apache.archiva.rest.api.model.*;
49 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
50 import org.apache.archiva.rest.api.services.BrowseService;
51 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
52 import org.apache.archiva.security.ArchivaSecurityException;
53 import org.apache.archiva.xml.XMLException;
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 @Named( value = "browse#versionMetadata" )
91 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
93 private ManagedRepositoryContent getManagedRepositoryContent(String id) throws RepositoryException
95 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
97 throw new RepositoryException( "Could not find repository "+id );
99 return repo.getContent();
103 public BrowseResult getRootGroups( String repositoryId )
104 throws ArchivaRestServiceException
106 List<String> selectedRepos = getSelectedRepos( repositoryId );
108 Set<String> namespaces = new LinkedHashSet<String>();
110 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
111 // it is located here to avoid the content repository implementation needing to do too much for what
112 // is essentially presentation code
113 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
114 RepositorySession repositorySession = null;
117 repositorySession = repositorySessionFactory.createSession();
119 catch ( MetadataRepositoryException e )
121 e.printStackTrace( );
125 MetadataResolver metadataResolver = repositorySession.getResolver();
127 for ( String repoId : selectedRepos )
129 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
131 for ( String n : namespacesToCollapse )
133 // TODO: check performance of this
134 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
137 catch ( MetadataResolutionException e )
139 throw new ArchivaRestServiceException( e.getMessage(),
140 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
144 repositorySession.close();
147 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
148 for ( String namespace : namespaces )
150 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
153 Collections.sort( browseGroupResultEntries );
154 return new BrowseResult( browseGroupResultEntries );
158 public BrowseResult browseGroupId( String groupId, String repositoryId )
159 throws ArchivaRestServiceException
161 List<String> selectedRepos = getSelectedRepos( repositoryId );
163 Set<String> projects = new LinkedHashSet<>();
165 RepositorySession repositorySession = null;
168 repositorySession = repositorySessionFactory.createSession();
170 catch ( MetadataRepositoryException e )
172 e.printStackTrace( );
174 Set<String> namespaces;
177 MetadataResolver metadataResolver = repositorySession.getResolver();
179 Set<String> namespacesToCollapse = new LinkedHashSet<>();
180 for ( String repoId : selectedRepos )
182 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
184 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
187 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
188 // it is located here to avoid the content repository implementation needing to do too much for what
189 // is essentially presentation code
190 namespaces = new LinkedHashSet<>();
191 for ( String n : namespacesToCollapse )
193 // TODO: check performance of this
195 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
198 catch ( MetadataResolutionException e )
200 throw new ArchivaRestServiceException( e.getMessage(),
201 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
205 repositorySession.close();
207 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
208 for ( String namespace : namespaces )
210 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
212 for ( String project : projects )
214 browseGroupResultEntries.add(
215 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
217 Collections.sort( browseGroupResultEntries );
218 return new BrowseResult( browseGroupResultEntries );
223 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
224 throws ArchivaRestServiceException
226 List<String> selectedRepos = getSelectedRepos( repositoryId );
230 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
231 return new VersionsList( new ArrayList<>( versions ) );
233 catch ( MetadataResolutionException e )
235 throw new ArchivaRestServiceException( e.getMessage(),
236 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
241 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
242 throws MetadataResolutionException
245 RepositorySession repositorySession = null;
248 repositorySession = repositorySessionFactory.createSession();
250 catch ( MetadataRepositoryException e )
252 e.printStackTrace( );
256 MetadataResolver metadataResolver = repositorySession.getResolver();
258 Set<String> versions = new LinkedHashSet<String>();
260 for ( String repoId : selectedRepos )
262 Collection<String> projectVersions =
263 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
264 versions.addAll( projectVersions );
267 List<String> sortedVersions = new ArrayList<>( versions );
269 Collections.sort( sortedVersions, VersionComparator.getInstance() );
271 return sortedVersions;
275 repositorySession.close();
280 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
281 String repositoryId )
282 throws ArchivaRestServiceException
284 List<String> selectedRepos = getSelectedRepos( repositoryId );
286 RepositorySession repositorySession = null;
289 repositorySession = repositorySessionFactory.createSession();
291 MetadataResolver metadataResolver = repositorySession.getResolver();
293 ProjectVersionMetadata versionMetadata = null;
294 for ( String repoId : selectedRepos )
296 if ( versionMetadata == null || versionMetadata.isIncomplete() )
300 ProjectVersionMetadata versionMetadataTmp =
301 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
304 if ( versionMetadata == null && versionMetadataTmp != null )
306 versionMetadata = versionMetadataTmp;
311 catch ( MetadataResolutionException e )
313 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
314 groupId, artifactId, repoId, e.getMessage() );
319 return versionMetadata;
320 } catch (MetadataRepositoryException e) {
321 throw new ArchivaRestServiceException(e.getMessage(), e);
324 if ( repositorySession != null )
326 repositorySession.close();
333 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
334 throws ArchivaRestServiceException
337 List<String> selectedRepos = getSelectedRepos( repositoryId );
339 RepositorySession repositorySession = null;
343 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
345 repositorySession = repositorySessionFactory.createSession();
347 MetadataResolver metadataResolver = repositorySession.getResolver();
349 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
351 MavenProjectFacet mavenFacet = new MavenProjectFacet();
352 mavenFacet.setGroupId( groupId );
353 mavenFacet.setArtifactId( artifactId );
354 sharedModel.addFacet( mavenFacet );
356 boolean isFirstVersion = true;
358 for ( String version : projectVersions )
360 ProjectVersionMetadata versionMetadata = null;
361 for ( String repoId : selectedRepos )
363 if ( versionMetadata == null || versionMetadata.isIncomplete() )
367 ProjectVersionMetadata projectVersionMetadataResolved = null;
368 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
369 String cacheKey = null;
370 boolean cacheToUpdate = false;
371 // FIXME a bit maven centric!!!
372 // not a snapshot so get it from cache
375 cacheKey = repoId + groupId + artifactId + version;
376 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
378 if ( useCache && projectVersionMetadataResolved != null )
380 versionMetadata = projectVersionMetadataResolved;
384 projectVersionMetadataResolved =
385 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
386 artifactId, version );
387 versionMetadata = projectVersionMetadataResolved;
388 cacheToUpdate = true;
391 if ( useCache && cacheToUpdate )
393 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
397 catch ( MetadataResolutionException e )
399 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
400 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
405 if ( versionMetadata == null )
410 if ( isFirstVersion )
412 sharedModel = versionMetadata;
413 sharedModel.setId( null );
417 MavenProjectFacet versionMetadataMavenFacet =
418 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
419 if ( versionMetadataMavenFacet != null )
421 if ( mavenFacet.getPackaging() != null //
422 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
423 versionMetadataMavenFacet.getPackaging() ) )
425 mavenFacet.setPackaging( null );
429 if ( StringUtils.isEmpty( sharedModel.getName() ) //
430 && !StringUtils.isEmpty( versionMetadata.getName() ) )
432 sharedModel.setName( versionMetadata.getName() );
435 if ( sharedModel.getDescription() != null //
436 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
437 versionMetadata.getDescription() ) )
439 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
440 ? versionMetadata.getDescription()
444 if ( sharedModel.getIssueManagement() != null //
445 && versionMetadata.getIssueManagement() != null //
446 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
447 versionMetadata.getIssueManagement().getUrl() ) )
449 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
452 if ( sharedModel.getCiManagement() != null //
453 && versionMetadata.getCiManagement() != null //
454 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
455 versionMetadata.getCiManagement().getUrl() ) )
457 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
460 if ( sharedModel.getOrganization() != null //
461 && versionMetadata.getOrganization() != null //
462 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
463 versionMetadata.getOrganization().getName() ) )
465 sharedModel.setOrganization( versionMetadata.getOrganization() );
468 if ( sharedModel.getUrl() != null //
469 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
471 sharedModel.setUrl( versionMetadata.getUrl() );
475 isFirstVersion = false;
479 catch (MetadataResolutionException | MetadataRepositoryException e )
481 throw new ArchivaRestServiceException( e.getMessage(),
482 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
486 if ( repositorySession != null )
488 repositorySession.close();
494 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
495 throws ArchivaRestServiceException
497 List<String> selectedRepos = getSelectedRepos( repositoryId );
501 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
503 catch ( Exception e )
505 log.error( e.getMessage(), e );
508 return Collections.emptyList();
512 public List<ManagedRepository> getUserRepositories()
513 throws ArchivaRestServiceException
517 return userRepositories.getAccessibleRepositories( getPrincipal() );
519 catch ( ArchivaSecurityException e )
521 throw new ArchivaRestServiceException( "repositories.read.observable.error",
522 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
527 public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
530 return userRepositories.getManagableRepositories( getPrincipal() );
532 catch ( ArchivaSecurityException e )
534 throw new ArchivaRestServiceException( "repositories.read.managable.error",
535 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
540 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
541 throws ArchivaRestServiceException
543 List<ProjectVersionReference> references = new ArrayList<>();
544 // TODO: what if we get duplicates across repositories?
545 RepositorySession repositorySession = null;
548 repositorySession = repositorySessionFactory.createSession();
550 catch ( MetadataRepositoryException e )
552 e.printStackTrace( );
556 MetadataResolver metadataResolver = repositorySession.getResolver();
557 for ( String repoId : getObservableRepos() )
559 // TODO: what about if we want to see this irrespective of version?
561 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
565 catch ( MetadataResolutionException e )
567 throw new ArchivaRestServiceException( e.getMessage(),
568 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
572 repositorySession.close();
575 List<Artifact> artifacts = new ArrayList<>( references.size() );
577 for ( ProjectVersionReference projectVersionReference : references )
579 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
580 projectVersionReference.getProjectVersion() ) );
586 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
587 throws ArchivaRestServiceException
589 ProjectVersionMetadata projectVersionMetadata =
590 getProjectMetadata( groupId, artifactId, version, repositoryId );
591 if ( projectVersionMetadata == null )
593 return Collections.emptyList();
595 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
597 if ( metadataFacet == null )
599 return Collections.emptyList();
601 Map<String, String> map = metadataFacet.toProperties();
602 List<Entry> entries = new ArrayList<>( map.size() );
604 for ( Map.Entry<String, String> entry : map.entrySet() )
606 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
613 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
614 String repositoryId )
615 throws ArchivaRestServiceException
617 ProjectVersionMetadata projectVersionMetadata =
618 getProjectMetadata( groupId, artifactId, version, repositoryId );
620 if ( projectVersionMetadata == null )
622 return Boolean.FALSE;
625 Map<String, String> properties = new HashMap<>();
627 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
629 if ( metadataFacet != null && metadataFacet.toProperties() != null )
631 properties.putAll( metadataFacet.toProperties() );
635 metadataFacet = new GenericMetadataFacet();
638 properties.put( key, value );
640 metadataFacet.fromProperties( properties );
642 projectVersionMetadata.addFacet( metadataFacet );
644 RepositorySession repositorySession = null;
647 repositorySession = repositorySessionFactory.createSession();
649 catch ( MetadataRepositoryException e )
651 e.printStackTrace( );
656 MetadataRepository metadataRepository = repositorySession.getRepository();
658 metadataRepository.updateProjectVersion(repositorySession , repositoryId, groupId, artifactId, projectVersionMetadata );
660 repositorySession.save();
662 catch (MetadataRepositoryException | MetadataSessionException e )
664 log.error( e.getMessage(), e );
665 throw new ArchivaRestServiceException( e.getMessage(),
666 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
670 repositorySession.close();
676 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
677 throws ArchivaRestServiceException
679 ProjectVersionMetadata projectVersionMetadata =
680 getProjectMetadata( groupId, artifactId, version, repositoryId );
682 if ( projectVersionMetadata == null )
684 return Boolean.FALSE;
687 GenericMetadataFacet metadataFacet =
688 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
690 if ( metadataFacet != null && metadataFacet.toProperties() != null )
692 Map<String, String> properties = metadataFacet.toProperties();
693 properties.remove( key );
694 metadataFacet.setAdditionalProperties( properties );
701 RepositorySession repositorySession = null;
704 repositorySession = repositorySessionFactory.createSession();
706 catch ( MetadataRepositoryException e )
708 e.printStackTrace( );
713 MetadataRepository metadataRepository = repositorySession.getRepository();
715 metadataRepository.updateProjectVersion(repositorySession , repositoryId, groupId, artifactId, projectVersionMetadata );
717 repositorySession.save();
719 catch (MetadataRepositoryException | MetadataSessionException e )
721 log.error( e.getMessage(), e );
722 throw new ArchivaRestServiceException( e.getMessage(),
723 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
727 repositorySession.close();
733 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
734 String classifier, String type, String path,
735 String repositoryId )
736 throws ArchivaRestServiceException
738 List<String> selectedRepos = getSelectedRepos( repositoryId );
741 for ( String repoId : selectedRepos )
744 ManagedRepositoryContent managedRepositoryContent =
745 getManagedRepositoryContent( repoId );
746 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
747 StringUtils.isEmpty( type ) ? "jar" : type,
749 StorageAsset file = managedRepositoryContent.toFile( archivaArtifact );
752 return readFileEntries( file, path, repoId );
756 catch ( IOException e )
758 log.error( e.getMessage(), e );
759 throw new ArchivaRestServiceException( e.getMessage(),
760 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
762 catch ( RepositoryNotFoundException e )
764 log.error( e.getMessage(), e );
765 throw new ArchivaRestServiceException( e.getMessage(),
766 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
768 catch ( RepositoryException e )
770 log.error( e.getMessage(), e );
771 throw new ArchivaRestServiceException( e.getMessage(),
772 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
774 return Collections.emptyList();
778 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
779 String repositoryId )
780 throws ArchivaRestServiceException
782 List<String> selectedRepos = getSelectedRepos( repositoryId );
784 List<Artifact> artifactDownloadInfos = new ArrayList<>();
786 try (RepositorySession session = repositorySessionFactory.createSession())
788 MetadataResolver metadataResolver = session.getResolver();
789 for ( String repoId : selectedRepos )
791 List<ArtifactMetadata> artifacts = new ArrayList<>(
792 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
793 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
794 if ( artifacts != null && !artifacts.isEmpty() )
796 return buildArtifacts( artifacts, repoId );
800 catch ( MetadataResolutionException e )
802 log.error( e.getMessage(), e );
803 throw new ArchivaRestServiceException( e.getMessage(),
804 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
806 catch ( MetadataRepositoryException e )
808 e.printStackTrace( );
811 return artifactDownloadInfos;
815 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
816 String type, String path, String repositoryId )
817 throws ArchivaRestServiceException
819 List<String> selectedRepos = getSelectedRepos( repositoryId );
822 for ( String repoId : selectedRepos )
825 ManagedRepositoryContent managedRepositoryContent = null;
828 managedRepositoryContent = getManagedRepositoryContent( repoId );
830 catch ( RepositoryException e )
832 log.error("No repository content found for "+repoId);
835 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
836 StringUtils.isEmpty( type ) ? "jar" : type,
838 StorageAsset file = managedRepositoryContent.toFile( archivaArtifact );
839 if ( !file.exists() )
841 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
844 if ( StringUtils.isNotBlank( path ) )
846 // zip entry of the path -> path must a real file entry of the archive
847 StorageUtil.PathInformation pathInfo = StorageUtil.getAssetDataAsPath(file);
848 JarFile jarFile = new JarFile( pathInfo.getPath().toFile());
849 ZipEntry zipEntry = jarFile.getEntry( path );
850 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
852 return new ArtifactContent( IOUtils.toString( inputStream, ARTIFACT_CONTENT_ENCODING ), repoId );
856 closeQuietly( jarFile );
857 if (pathInfo.isTmpFile()) {
858 Files.deleteIfExists(pathInfo.getPath());
862 try(InputStream readStream = file.getReadStream()) {
863 return new ArtifactContent(IOUtils.toString(readStream, ARTIFACT_CONTENT_ENCODING), repoId);
867 catch ( IOException e )
869 log.error( e.getMessage(), e );
870 throw new ArchivaRestServiceException( e.getMessage(),
871 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
873 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
875 return new ArtifactContent();
879 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
880 String repositoryId )
881 throws ArchivaRestServiceException
883 List<String> selectedRepos = getSelectedRepos( repositoryId );
885 boolean snapshot = VersionUtil.isSnapshot( version );
889 for ( String repoId : selectedRepos )
892 org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repoId);
893 if (!proxyRegistry.hasHandler(managedRepo.getType())) {
894 throw new RepositoryException( "No proxy handler found for repository type "+managedRepo.getType());
896 RepositoryProxyHandler proxyHandler = proxyRegistry.getHandler(managedRepo.getType()).get(0);
897 if ( ( snapshot && !managedRepo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) ) || ( !snapshot
898 && managedRepo.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT) ) )
902 ManagedRepositoryContent managedRepositoryContent = getManagedRepositoryContent( repoId );
904 // FIXME default to jar which can be wrong for war zip etc....
905 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
906 StringUtils.isEmpty( classifier )
908 : classifier, "jar", repoId );
909 StorageAsset file = managedRepositoryContent.toFile( archivaArtifact );
911 if ( file != null && file.exists() )
916 // in case of SNAPSHOT we can have timestamped version locally !
917 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
919 StorageAsset metadataFile = file.getStorage().getAsset(file.getParent().getPath()+"/"+MetadataTools.MAVEN_METADATA );
920 if ( metadataFile.exists() )
924 ArchivaRepositoryMetadata archivaRepositoryMetadata =
925 MavenMetadataReader.read( metadataFile );
926 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
927 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
928 // rebuild file name with timestamped version and build number
929 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
930 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
931 .append( '-' ).append( timeStamp ) //
932 .append( '-' ).append( Integer.toString( buildNumber ) ) //
933 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
934 .append( ".jar" ).toString();
936 StorageAsset timeStampFile = file.getStorage().getAsset(file.getParent().getPath() + "/" + timeStampFileName );
937 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
938 if ( timeStampFile.exists() )
943 catch (XMLException | IOException e )
945 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
950 String path = managedRepositoryContent.toPath( archivaArtifact );
952 file = proxyHandler.fetchFromProxies( managedRepositoryContent.getRepository(), path );
954 if ( file != null && file.exists() )
957 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
958 proxyHandler.fetchFromProxies( managedRepositoryContent.getRepository(), pomPath );
962 } catch ( RepositoryException e )
964 log.error( e.getMessage(), e );
965 throw new ArchivaRestServiceException( e.getMessage(),
966 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
973 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
974 throws ArchivaRestServiceException
976 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
980 public List<Artifact> getArtifacts( String repositoryId )
981 throws ArchivaRestServiceException
983 RepositorySession repositorySession = null;
986 repositorySession = repositorySessionFactory.createSession();
988 catch ( MetadataRepositoryException e )
990 e.printStackTrace( );
994 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts(repositorySession , repositoryId );
995 return buildArtifacts( artifactMetadatas, repositoryId );
997 catch ( MetadataRepositoryException e )
999 throw new ArchivaRestServiceException( e.getMessage(), e );
1003 repositorySession.close();
1008 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
1009 throws ArchivaRestServiceException
1011 RepositorySession repositorySession = null;
1014 repositorySession = repositorySessionFactory.createSession();
1016 catch ( MetadataRepositoryException e )
1018 e.printStackTrace( );
1022 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionFacet(repositorySession , key, value, repositoryId );
1023 return buildArtifacts( artifactMetadatas, repositoryId );
1025 catch ( MetadataRepositoryException e )
1027 throw new ArchivaRestServiceException( e.getMessage(), e );
1031 repositorySession.close();
1036 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
1037 throws ArchivaRestServiceException
1039 RepositorySession repositorySession = null;
1042 repositorySession = repositorySessionFactory.createSession();
1044 catch ( MetadataRepositoryException e )
1046 e.printStackTrace( );
1050 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByAttribute(repositorySession , key, value, repositoryId );
1051 return buildArtifacts( artifactMetadatas, repositoryId );
1053 catch ( MetadataRepositoryException e )
1055 throw new ArchivaRestServiceException( e.getMessage(), e );
1059 repositorySession.close();
1064 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
1065 throws ArchivaRestServiceException
1067 RepositorySession repositorySession = null;
1070 repositorySession = repositorySessionFactory.createSession();
1072 catch ( MetadataRepositoryException e )
1074 e.printStackTrace( );
1078 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionAttribute(repositorySession , key, value, repositoryId );
1079 return buildArtifacts( artifactMetadatas, repositoryId );
1081 catch ( MetadataRepositoryException e )
1083 throw new ArchivaRestServiceException( e.getMessage(), e );
1087 repositorySession.close();
1092 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1093 throws ArchivaRestServiceException
1095 boolean result = true;
1096 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1098 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1099 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1110 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1111 throws ArchivaRestServiceException
1113 try(RepositorySession repositorySession = repositorySessionFactory.createSession())
1115 List<ArtifactMetadata> artifactMetadatas =
1116 repositorySession.getRepository().searchArtifacts(repositorySession , repositoryId, text, exact == null ? false : exact );
1117 return buildArtifacts( artifactMetadatas, repositoryId );
1119 catch ( MetadataRepositoryException e )
1121 throw new ArchivaRestServiceException( e.getMessage(), e );
1126 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1127 throws ArchivaRestServiceException
1129 RepositorySession repositorySession = null;
1132 repositorySession = repositorySessionFactory.createSession();
1134 catch ( MetadataRepositoryException e )
1136 e.printStackTrace( );
1140 List<ArtifactMetadata> artifactMetadatas =
1141 repositorySession.getRepository().searchArtifacts(repositorySession , repositoryId, key, text, exact == null ? false : exact );
1142 return buildArtifacts( artifactMetadatas, repositoryId );
1144 catch ( MetadataRepositoryException e )
1146 throw new ArchivaRestServiceException( e.getMessage(), e );
1150 repositorySession.close();
1154 //---------------------------
1156 //---------------------------
1158 private void closeQuietly( JarFile jarFile )
1160 if ( jarFile != null )
1166 catch ( IOException e )
1168 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1173 protected List<ArtifactContentEntry> readFileEntries(final StorageAsset file, final String filterPath, final String repoId )
1176 String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
1177 StringUtils.substringAfter(filterPath, "/") : filterPath);
1178 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1179 int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
1180 if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
1184 StorageUtil.PathInformation pathInfo = StorageUtil.getAssetDataAsPath(file);
1185 JarFile jarFile = new JarFile(pathInfo.getPath().toFile());
1188 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1189 while ( jarEntryEnumeration.hasMoreElements() )
1191 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1192 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
1193 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1194 String entryRootPath = getRootPath( cleanedEntryName );
1195 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1196 if ( StringUtils.isEmpty( cleanedfilterPath ) //
1197 && !artifactContentEntryMap.containsKey( entryRootPath ) //
1198 && depth == filterDepth )
1201 artifactContentEntryMap.put( entryRootPath,
1202 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1207 if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath ) //
1208 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1210 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1211 !currentEntry.isDirectory(),
1217 if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
1219 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1221 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1223 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1226 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1227 if ( sorted == null )
1229 return Collections.emptyList();
1231 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1237 if ( jarFile != null )
1241 if (pathInfo.isTmpFile()) {
1242 Files.deleteIfExists(pathInfo.getPath());
1245 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1246 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1250 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1252 int smallestDepth = Integer.MAX_VALUE;
1253 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1254 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1257 ArtifactContentEntry current = entry.getValue();
1259 if ( current.getDepth() < smallestDepth )
1261 smallestDepth = current.getDepth();
1264 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1266 if ( currentList == null )
1268 currentList = new ArrayList<>();
1269 currentList.add( current );
1270 perDepthList.put( current.getDepth(), currentList );
1274 currentList.add( current );
1279 return perDepthList.get( smallestDepth );
1284 * @return org/apache -> org , org -> org
1286 private String getRootPath( String path )
1288 if ( StringUtils.contains( path, '/' ) )
1290 return StringUtils.substringBefore( path, "/" );
1295 private List<String> getSelectedRepos( String repositoryId )
1296 throws ArchivaRestServiceException
1299 List<String> selectedRepos = getObservableRepos();
1301 if ( CollectionUtils.isEmpty( selectedRepos ) )
1303 return Collections.emptyList();
1306 if ( StringUtils.isNotEmpty( repositoryId ) )
1308 // check user has karma on the repository
1309 if ( !selectedRepos.contains( repositoryId ) )
1311 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1312 Response.Status.FORBIDDEN.getStatusCode(), null );
1314 selectedRepos = Collections.singletonList( repositoryId );
1316 return selectedRepos;
1320 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1321 Collection<String> repoIds, String n )
1322 throws MetadataResolutionException
1324 Set<String> subNamespaces = new LinkedHashSet<String>();
1325 for ( String repoId : repoIds )
1327 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1329 if ( subNamespaces.size() != 1 )
1331 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1336 for ( String repoId : repoIds )
1338 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1339 if ( projects != null && !projects.isEmpty() )
1341 log.debug( "{} is not collapsible as it has projects", n );
1345 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1346 n + "." + subNamespaces.iterator().next() );
1350 public Cache<String, ProjectVersionMetadata> getVersionMetadataCache()
1352 return versionMetadataCache;
1355 public void setVersionMetadataCache( Cache<String, ProjectVersionMetadata> versionMetadataCache )
1357 this.versionMetadataCache = versionMetadataCache;