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.RepositoryAdminException;
22 import org.apache.archiva.admin.model.beans.ManagedRepository;
23 import org.apache.archiva.common.utils.VersionComparator;
24 import org.apache.archiva.common.utils.VersionUtil;
25 import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder;
26 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
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.MetadataRepository;
35 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
36 import org.apache.archiva.metadata.repository.MetadataResolutionException;
37 import org.apache.archiva.metadata.repository.MetadataResolver;
38 import org.apache.archiva.metadata.repository.RepositorySession;
39 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
40 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
41 import org.apache.archiva.model.ArchivaArtifact;
42 import org.apache.archiva.model.ArchivaRepositoryMetadata;
43 import org.apache.archiva.proxy.model.RepositoryProxyConnectors;
44 import org.apache.archiva.redback.components.cache.Cache;
45 import org.apache.archiva.repository.ManagedRepositoryContent;
46 import org.apache.archiva.repository.RepositoryContentFactory;
47 import org.apache.archiva.repository.RepositoryException;
48 import org.apache.archiva.repository.RepositoryNotFoundException;
49 import org.apache.archiva.repository.metadata.MetadataTools;
50 import org.apache.archiva.rest.api.model.ArtifactContent;
51 import org.apache.archiva.rest.api.model.ArtifactContentEntry;
52 import org.apache.archiva.rest.api.model.BrowseResult;
53 import org.apache.archiva.rest.api.model.BrowseResultEntry;
54 import org.apache.archiva.rest.api.model.Entry;
55 import org.apache.archiva.rest.api.model.MetadataAddRequest;
56 import org.apache.archiva.rest.api.model.VersionsList;
57 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
58 import org.apache.archiva.rest.api.services.BrowseService;
59 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
60 import org.apache.archiva.security.ArchivaSecurityException;
61 import org.apache.archiva.xml.XMLException;
62 import org.apache.commons.collections.CollectionUtils;
63 import org.apache.commons.io.FileUtils;
64 import org.apache.commons.io.IOUtils;
65 import org.apache.commons.lang.StringUtils;
66 import org.springframework.stereotype.Service;
68 import javax.inject.Inject;
69 import javax.inject.Named;
70 import javax.ws.rs.core.Response;
72 import java.io.IOException;
73 import java.io.InputStream;
74 import java.nio.charset.Charset;
75 import java.nio.file.Files;
76 import java.nio.file.Path;
77 import java.util.ArrayList;
78 import java.util.Collection;
79 import java.util.Collections;
80 import java.util.Enumeration;
81 import java.util.HashMap;
82 import java.util.LinkedHashSet;
83 import java.util.List;
86 import java.util.jar.JarEntry;
87 import java.util.jar.JarFile;
88 import java.util.zip.ZipEntry;
91 * @author Olivier Lamy
94 @Service( "browseService#rest" )
95 public class DefaultBrowseService
96 extends AbstractRestService
97 implements BrowseService
100 private Charset ARTIFACT_CONTENT_ENCODING=Charset.forName( "UTF-8" );
103 private DependencyTreeBuilder dependencyTreeBuilder;
106 private RepositoryContentFactory repositoryContentFactory;
109 @Named( value = "repositoryProxyConnectors#default" )
110 private RepositoryProxyConnectors connectors;
113 @Named( value = "browse#versionMetadata" )
114 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
117 public BrowseResult getRootGroups( String repositoryId )
118 throws ArchivaRestServiceException
120 List<String> selectedRepos = getSelectedRepos( repositoryId );
122 Set<String> namespaces = new LinkedHashSet<String>();
124 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
125 // it is located here to avoid the content repository implementation needing to do too much for what
126 // is essentially presentation code
127 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
128 RepositorySession repositorySession = repositorySessionFactory.createSession();
131 MetadataResolver metadataResolver = repositorySession.getResolver();
133 for ( String repoId : selectedRepos )
135 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
137 for ( String n : namespacesToCollapse )
139 // TODO: check performance of this
140 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
143 catch ( MetadataResolutionException e )
145 throw new ArchivaRestServiceException( e.getMessage(),
146 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
150 repositorySession.close();
153 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
154 for ( String namespace : namespaces )
156 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
159 Collections.sort( browseGroupResultEntries );
160 return new BrowseResult( browseGroupResultEntries );
164 public BrowseResult browseGroupId( String groupId, String repositoryId )
165 throws ArchivaRestServiceException
167 List<String> selectedRepos = getSelectedRepos( repositoryId );
169 Set<String> projects = new LinkedHashSet<>();
171 RepositorySession repositorySession = repositorySessionFactory.createSession();
172 Set<String> namespaces;
175 MetadataResolver metadataResolver = repositorySession.getResolver();
177 Set<String> namespacesToCollapse = new LinkedHashSet<>();
178 for ( String repoId : selectedRepos )
180 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
182 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
185 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
186 // it is located here to avoid the content repository implementation needing to do too much for what
187 // is essentially presentation code
188 namespaces = new LinkedHashSet<>();
189 for ( String n : namespacesToCollapse )
191 // TODO: check performance of this
193 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
196 catch ( MetadataResolutionException e )
198 throw new ArchivaRestServiceException( e.getMessage(),
199 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
203 repositorySession.close();
205 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
206 for ( String namespace : namespaces )
208 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
210 for ( String project : projects )
212 browseGroupResultEntries.add(
213 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
215 Collections.sort( browseGroupResultEntries );
216 return new BrowseResult( browseGroupResultEntries );
221 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
222 throws ArchivaRestServiceException
224 List<String> selectedRepos = getSelectedRepos( repositoryId );
228 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
229 return new VersionsList( new ArrayList<>( versions ) );
231 catch ( MetadataResolutionException e )
233 throw new ArchivaRestServiceException( e.getMessage(),
234 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
239 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
240 throws MetadataResolutionException
243 RepositorySession repositorySession = repositorySessionFactory.createSession();
246 MetadataResolver metadataResolver = repositorySession.getResolver();
248 Set<String> versions = new LinkedHashSet<String>();
250 for ( String repoId : selectedRepos )
252 Collection<String> projectVersions =
253 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
254 versions.addAll( projectVersions );
257 List<String> sortedVersions = new ArrayList<>( versions );
259 Collections.sort( sortedVersions, VersionComparator.getInstance() );
261 return sortedVersions;
265 repositorySession.close();
270 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
271 String repositoryId )
272 throws ArchivaRestServiceException
274 List<String> selectedRepos = getSelectedRepos( repositoryId );
276 RepositorySession repositorySession = null;
279 repositorySession = repositorySessionFactory.createSession();
281 MetadataResolver metadataResolver = repositorySession.getResolver();
283 ProjectVersionMetadata versionMetadata = null;
284 for ( String repoId : selectedRepos )
286 if ( versionMetadata == null || versionMetadata.isIncomplete() )
290 ProjectVersionMetadata versionMetadataTmp =
291 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
294 if ( versionMetadata == null && versionMetadataTmp != null )
296 versionMetadata = versionMetadataTmp;
301 catch ( MetadataResolutionException e )
303 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
304 groupId, artifactId, repoId, e.getMessage() );
309 return versionMetadata;
313 if ( repositorySession != null )
315 repositorySession.close();
322 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
323 throws ArchivaRestServiceException
326 List<String> selectedRepos = getSelectedRepos( repositoryId );
328 RepositorySession repositorySession = null;
332 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
334 repositorySession = repositorySessionFactory.createSession();
336 MetadataResolver metadataResolver = repositorySession.getResolver();
338 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
340 MavenProjectFacet mavenFacet = new MavenProjectFacet();
341 mavenFacet.setGroupId( groupId );
342 mavenFacet.setArtifactId( artifactId );
343 sharedModel.addFacet( mavenFacet );
345 boolean isFirstVersion = true;
347 for ( String version : projectVersions )
349 ProjectVersionMetadata versionMetadata = null;
350 for ( String repoId : selectedRepos )
352 if ( versionMetadata == null || versionMetadata.isIncomplete() )
356 ProjectVersionMetadata projectVersionMetadataResolved = null;
357 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
358 String cacheKey = null;
359 boolean cacheToUpdate = false;
360 // FIXME a bit maven centric!!!
361 // not a snapshot so get it from cache
364 cacheKey = repoId + groupId + artifactId + version;
365 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
367 if ( useCache && projectVersionMetadataResolved != null )
369 versionMetadata = projectVersionMetadataResolved;
373 projectVersionMetadataResolved =
374 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
375 artifactId, version );
376 versionMetadata = projectVersionMetadataResolved;
377 cacheToUpdate = true;
380 if ( useCache && cacheToUpdate )
382 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
386 catch ( MetadataResolutionException e )
388 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
389 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
394 if ( versionMetadata == null )
399 if ( isFirstVersion )
401 sharedModel = versionMetadata;
402 sharedModel.setId( null );
406 MavenProjectFacet versionMetadataMavenFacet =
407 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
408 if ( versionMetadataMavenFacet != null )
410 if ( mavenFacet.getPackaging() != null //
411 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
412 versionMetadataMavenFacet.getPackaging() ) )
414 mavenFacet.setPackaging( null );
418 if ( StringUtils.isEmpty( sharedModel.getName() ) //
419 && !StringUtils.isEmpty( versionMetadata.getName() ) )
421 sharedModel.setName( versionMetadata.getName() );
424 if ( sharedModel.getDescription() != null //
425 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
426 versionMetadata.getDescription() ) )
428 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
429 ? versionMetadata.getDescription()
433 if ( sharedModel.getIssueManagement() != null //
434 && versionMetadata.getIssueManagement() != null //
435 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
436 versionMetadata.getIssueManagement().getUrl() ) )
438 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
441 if ( sharedModel.getCiManagement() != null //
442 && versionMetadata.getCiManagement() != null //
443 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
444 versionMetadata.getCiManagement().getUrl() ) )
446 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
449 if ( sharedModel.getOrganization() != null //
450 && versionMetadata.getOrganization() != null //
451 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
452 versionMetadata.getOrganization().getName() ) )
454 sharedModel.setOrganization( versionMetadata.getOrganization() );
457 if ( sharedModel.getUrl() != null //
458 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
460 sharedModel.setUrl( versionMetadata.getUrl() );
464 isFirstVersion = false;
468 catch ( MetadataResolutionException e )
470 throw new ArchivaRestServiceException( e.getMessage(),
471 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
475 if ( repositorySession != null )
477 repositorySession.close();
483 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
484 throws ArchivaRestServiceException
486 List<String> selectedRepos = getSelectedRepos( repositoryId );
490 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
492 catch ( Exception e )
494 log.error( e.getMessage(), e );
497 return Collections.emptyList();
501 public List<ManagedRepository> getUserRepositories()
502 throws ArchivaRestServiceException
506 return userRepositories.getAccessibleRepositories( getPrincipal() );
508 catch ( ArchivaSecurityException e )
510 throw new ArchivaRestServiceException( "repositories.read.observable.error",
511 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
516 public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
519 return userRepositories.getManagableRepositories( getPrincipal() );
521 catch ( ArchivaSecurityException e )
523 throw new ArchivaRestServiceException( "repositories.read.managable.error",
524 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
529 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
530 throws ArchivaRestServiceException
532 List<ProjectVersionReference> references = new ArrayList<>();
533 // TODO: what if we get duplicates across repositories?
534 RepositorySession repositorySession = repositorySessionFactory.createSession();
537 MetadataResolver metadataResolver = repositorySession.getResolver();
538 for ( String repoId : getObservableRepos() )
540 // TODO: what about if we want to see this irrespective of version?
542 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
546 catch ( MetadataResolutionException e )
548 throw new ArchivaRestServiceException( e.getMessage(),
549 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
553 repositorySession.close();
556 List<Artifact> artifacts = new ArrayList<>( references.size() );
558 for ( ProjectVersionReference projectVersionReference : references )
560 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
561 projectVersionReference.getProjectVersion() ) );
567 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
568 throws ArchivaRestServiceException
570 ProjectVersionMetadata projectVersionMetadata =
571 getProjectMetadata( groupId, artifactId, version, repositoryId );
572 if ( projectVersionMetadata == null )
574 return Collections.emptyList();
576 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
578 if ( metadataFacet == null )
580 return Collections.emptyList();
582 Map<String, String> map = metadataFacet.toProperties();
583 List<Entry> entries = new ArrayList<>( map.size() );
585 for ( Map.Entry<String, String> entry : map.entrySet() )
587 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
594 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
595 String repositoryId )
596 throws ArchivaRestServiceException
598 ProjectVersionMetadata projectVersionMetadata =
599 getProjectMetadata( groupId, artifactId, version, repositoryId );
601 if ( projectVersionMetadata == null )
603 return Boolean.FALSE;
606 Map<String, String> properties = new HashMap<>();
608 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
610 if ( metadataFacet != null && metadataFacet.toProperties() != null )
612 properties.putAll( metadataFacet.toProperties() );
616 metadataFacet = new GenericMetadataFacet();
619 properties.put( key, value );
621 metadataFacet.fromProperties( properties );
623 projectVersionMetadata.addFacet( metadataFacet );
625 RepositorySession repositorySession = repositorySessionFactory.createSession();
629 MetadataRepository metadataRepository = repositorySession.getRepository();
631 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
633 repositorySession.save();
635 catch ( MetadataRepositoryException e )
637 log.error( e.getMessage(), e );
638 throw new ArchivaRestServiceException( e.getMessage(),
639 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
643 repositorySession.close();
649 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
650 throws ArchivaRestServiceException
652 ProjectVersionMetadata projectVersionMetadata =
653 getProjectMetadata( groupId, artifactId, version, repositoryId );
655 if ( projectVersionMetadata == null )
657 return Boolean.FALSE;
660 GenericMetadataFacet metadataFacet =
661 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
663 if ( metadataFacet != null && metadataFacet.toProperties() != null )
665 Map<String, String> properties = metadataFacet.toProperties();
666 properties.remove( key );
667 metadataFacet.setAdditionalProperties( properties );
674 RepositorySession repositorySession = repositorySessionFactory.createSession();
678 MetadataRepository metadataRepository = repositorySession.getRepository();
680 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
682 repositorySession.save();
684 catch ( MetadataRepositoryException e )
686 log.error( e.getMessage(), e );
687 throw new ArchivaRestServiceException( e.getMessage(),
688 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
692 repositorySession.close();
698 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
699 String classifier, String type, String path,
700 String repositoryId )
701 throws ArchivaRestServiceException
703 List<String> selectedRepos = getSelectedRepos( repositoryId );
706 for ( String repoId : selectedRepos )
709 ManagedRepositoryContent managedRepositoryContent =
710 repositoryContentFactory.getManagedRepositoryContent( repoId );
711 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
712 StringUtils.isEmpty( type ) ? "jar" : type,
714 Path file = managedRepositoryContent.toFile( archivaArtifact );
715 if ( Files.exists(file) )
717 return readFileEntries( file, path, repoId );
721 catch ( IOException e )
723 log.error( e.getMessage(), e );
724 throw new ArchivaRestServiceException( e.getMessage(),
725 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
727 catch ( RepositoryNotFoundException e )
729 log.error( e.getMessage(), e );
730 throw new ArchivaRestServiceException( e.getMessage(),
731 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
733 catch ( RepositoryException e )
735 log.error( e.getMessage(), e );
736 throw new ArchivaRestServiceException( e.getMessage(),
737 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
739 return Collections.emptyList();
743 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
744 String repositoryId )
745 throws ArchivaRestServiceException
747 List<String> selectedRepos = getSelectedRepos( repositoryId );
749 List<Artifact> artifactDownloadInfos = new ArrayList<>();
751 try (RepositorySession session = repositorySessionFactory.createSession())
753 MetadataResolver metadataResolver = session.getResolver();
754 for ( String repoId : selectedRepos )
756 List<ArtifactMetadata> artifacts = new ArrayList<>(
757 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
758 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
759 if ( artifacts != null && !artifacts.isEmpty() )
761 return buildArtifacts( artifacts, repoId );
765 catch ( MetadataResolutionException e )
767 log.error( e.getMessage(), e );
768 throw new ArchivaRestServiceException( e.getMessage(),
769 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
772 return artifactDownloadInfos;
776 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
777 String type, String path, String repositoryId )
778 throws ArchivaRestServiceException
780 List<String> selectedRepos = getSelectedRepos( repositoryId );
783 for ( String repoId : selectedRepos )
786 ManagedRepositoryContent managedRepositoryContent =
787 repositoryContentFactory.getManagedRepositoryContent( repoId );
788 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
789 StringUtils.isEmpty( type ) ? "jar" : type,
791 Path file = managedRepositoryContent.toFile( archivaArtifact );
792 if ( !Files.exists(file) )
794 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
797 if ( StringUtils.isNotBlank( path ) )
799 // zip entry of the path -> path must a real file entry of the archive
800 JarFile jarFile = new JarFile( file.toFile() );
801 ZipEntry zipEntry = jarFile.getEntry( path );
802 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
804 return new ArtifactContent( IOUtils.toString( inputStream, ARTIFACT_CONTENT_ENCODING ), repoId );
808 closeQuietly( jarFile );
811 return new ArtifactContent( new String(Files.readAllBytes( file ), ARTIFACT_CONTENT_ENCODING), repoId );
814 catch ( IOException e )
816 log.error( e.getMessage(), e );
817 throw new ArchivaRestServiceException( e.getMessage(),
818 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
820 catch ( RepositoryNotFoundException e )
822 log.error( e.getMessage(), e );
823 throw new ArchivaRestServiceException( e.getMessage(),
824 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
826 catch ( RepositoryException e )
828 log.error( e.getMessage(), e );
829 throw new ArchivaRestServiceException( e.getMessage(),
830 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
832 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
834 return new ArtifactContent();
838 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
839 String repositoryId )
840 throws ArchivaRestServiceException
842 List<String> selectedRepos = getSelectedRepos( repositoryId );
844 boolean snapshot = VersionUtil.isSnapshot( version );
848 for ( String repoId : selectedRepos )
851 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
853 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
854 && managedRepository.isSnapshots() ) )
858 ManagedRepositoryContent managedRepositoryContent =
859 repositoryContentFactory.getManagedRepositoryContent( repoId );
860 // FIXME default to jar which can be wrong for war zip etc....
861 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
862 StringUtils.isEmpty( classifier )
864 : classifier, "jar", repoId );
865 Path file = managedRepositoryContent.toFile( archivaArtifact );
867 if ( file != null && Files.exists(file) )
872 // in case of SNAPSHOT we can have timestamped version locally !
873 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
875 Path metadataFile = file.getParent().resolve(MetadataTools.MAVEN_METADATA );
876 if ( Files.exists(metadataFile) )
880 ArchivaRepositoryMetadata archivaRepositoryMetadata =
881 MavenMetadataReader.read( metadataFile );
882 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
883 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
884 // rebuild file name with timestamped version and build number
885 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
886 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
887 .append( '-' ).append( timeStamp ) //
888 .append( '-' ).append( Integer.toString( buildNumber ) ) //
889 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
890 .append( ".jar" ).toString();
892 Path timeStampFile = file.getParent().resolve( timeStampFileName );
893 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.toAbsolutePath() );
894 if ( Files.exists(timeStampFile) )
899 catch ( XMLException e )
901 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
906 String path = managedRepositoryContent.toPath( archivaArtifact );
908 file = connectors.fetchFromProxies( managedRepositoryContent, path );
910 if ( file != null && Files.exists(file) )
913 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
914 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
919 catch ( RepositoryAdminException e )
921 log.error( e.getMessage(), e );
922 throw new ArchivaRestServiceException( e.getMessage(),
923 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
925 catch ( RepositoryException e )
927 log.error( e.getMessage(), e );
928 throw new ArchivaRestServiceException( e.getMessage(),
929 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
936 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
937 throws ArchivaRestServiceException
939 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
943 public List<Artifact> getArtifacts( String repositoryId )
944 throws ArchivaRestServiceException
946 RepositorySession repositorySession = repositorySessionFactory.createSession();
949 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
950 return buildArtifacts( artifactMetadatas, repositoryId );
952 catch ( MetadataRepositoryException e )
954 throw new ArchivaRestServiceException( e.getMessage(), e );
958 repositorySession.close();
963 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
964 throws ArchivaRestServiceException
966 RepositorySession repositorySession = repositorySessionFactory.createSession();
969 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionMetadata( key, value, repositoryId );
970 return buildArtifacts( artifactMetadatas, repositoryId );
972 catch ( MetadataRepositoryException e )
974 throw new ArchivaRestServiceException( e.getMessage(), e );
978 repositorySession.close();
983 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
984 throws ArchivaRestServiceException
986 RepositorySession repositorySession = repositorySessionFactory.createSession();
989 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata( key, value, repositoryId );
990 return buildArtifacts( artifactMetadatas, repositoryId );
992 catch ( MetadataRepositoryException e )
994 throw new ArchivaRestServiceException( e.getMessage(), e );
998 repositorySession.close();
1003 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
1004 throws ArchivaRestServiceException
1006 RepositorySession repositorySession = repositorySessionFactory.createSession();
1009 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty( key, value, repositoryId );
1010 return buildArtifacts( artifactMetadatas, repositoryId );
1012 catch ( MetadataRepositoryException e )
1014 throw new ArchivaRestServiceException( e.getMessage(), e );
1018 repositorySession.close();
1023 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1024 throws ArchivaRestServiceException
1026 boolean result = true;
1027 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1029 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1030 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1041 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1042 throws ArchivaRestServiceException
1044 RepositorySession repositorySession = repositorySessionFactory.createSession();
1047 List<ArtifactMetadata> artifactMetadatas =
1048 repositorySession.getRepository().searchArtifacts( text, repositoryId, exact == null ? false : exact );
1049 return buildArtifacts( artifactMetadatas, repositoryId );
1051 catch ( MetadataRepositoryException e )
1053 throw new ArchivaRestServiceException( e.getMessage(), e );
1057 repositorySession.close();
1062 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1063 throws ArchivaRestServiceException
1065 RepositorySession repositorySession = repositorySessionFactory.createSession();
1068 List<ArtifactMetadata> artifactMetadatas =
1069 repositorySession.getRepository().searchArtifacts( key, text, repositoryId, exact == null ? false : exact );
1070 return buildArtifacts( artifactMetadatas, repositoryId );
1072 catch ( MetadataRepositoryException e )
1074 throw new ArchivaRestServiceException( e.getMessage(), e );
1078 repositorySession.close();
1082 //---------------------------
1084 //---------------------------
1086 private void closeQuietly( JarFile jarFile )
1088 if ( jarFile != null )
1094 catch ( IOException e )
1096 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1101 protected List<ArtifactContentEntry> readFileEntries(final Path file, final String filterPath, final String repoId )
1104 String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
1105 StringUtils.substringAfter(filterPath, "/") : filterPath);
1106 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1107 int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
1108 if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
1111 JarFile jarFile = new JarFile( file.toFile() );
1114 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1115 while ( jarEntryEnumeration.hasMoreElements() )
1117 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1118 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
1119 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1120 String entryRootPath = getRootPath( cleanedEntryName );
1121 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1122 if ( StringUtils.isEmpty( cleanedfilterPath ) //
1123 && !artifactContentEntryMap.containsKey( entryRootPath ) //
1124 && depth == filterDepth )
1127 artifactContentEntryMap.put( entryRootPath,
1128 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1133 if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath ) //
1134 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1136 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1137 !currentEntry.isDirectory(),
1143 if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
1145 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1147 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1149 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1152 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1153 if ( sorted == null )
1155 return Collections.emptyList();
1157 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1163 if ( jarFile != null )
1168 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1169 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1173 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1175 int smallestDepth = Integer.MAX_VALUE;
1176 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1177 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1180 ArtifactContentEntry current = entry.getValue();
1182 if ( current.getDepth() < smallestDepth )
1184 smallestDepth = current.getDepth();
1187 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1189 if ( currentList == null )
1191 currentList = new ArrayList<>();
1192 currentList.add( current );
1193 perDepthList.put( current.getDepth(), currentList );
1197 currentList.add( current );
1202 return perDepthList.get( smallestDepth );
1207 * @return org/apache -> org , org -> org
1209 private String getRootPath( String path )
1211 if ( StringUtils.contains( path, '/' ) )
1213 return StringUtils.substringBefore( path, "/" );
1218 private List<String> getSelectedRepos( String repositoryId )
1219 throws ArchivaRestServiceException
1222 List<String> selectedRepos = getObservableRepos();
1224 if ( CollectionUtils.isEmpty( selectedRepos ) )
1226 return Collections.emptyList();
1229 if ( StringUtils.isNotEmpty( repositoryId ) )
1231 // check user has karma on the repository
1232 if ( !selectedRepos.contains( repositoryId ) )
1234 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1235 Response.Status.FORBIDDEN.getStatusCode(), null );
1237 selectedRepos = Collections.singletonList( repositoryId );
1239 return selectedRepos;
1243 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1244 Collection<String> repoIds, String n )
1245 throws MetadataResolutionException
1247 Set<String> subNamespaces = new LinkedHashSet<String>();
1248 for ( String repoId : repoIds )
1250 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1252 if ( subNamespaces.size() != 1 )
1254 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1259 for ( String repoId : repoIds )
1261 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1262 if ( projects != null && !projects.isEmpty() )
1264 log.debug( "{} is not collapsible as it has projects", n );
1268 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1269 n + "." + subNamespaces.iterator().next() );
1273 public Cache getVersionMetadataCache()
1275 return versionMetadataCache;
1278 public void setVersionMetadataCache( Cache versionMetadataCache )
1280 this.versionMetadataCache = versionMetadataCache;