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.RepositoryException;
47 import org.apache.archiva.repository.RepositoryNotFoundException;
48 import org.apache.archiva.repository.metadata.MetadataTools;
49 import org.apache.archiva.rest.api.model.ArtifactContent;
50 import org.apache.archiva.rest.api.model.ArtifactContentEntry;
51 import org.apache.archiva.rest.api.model.BrowseResult;
52 import org.apache.archiva.rest.api.model.BrowseResultEntry;
53 import org.apache.archiva.rest.api.model.Entry;
54 import org.apache.archiva.rest.api.model.MetadataAddRequest;
55 import org.apache.archiva.rest.api.model.VersionsList;
56 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
57 import org.apache.archiva.rest.api.services.BrowseService;
58 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
59 import org.apache.archiva.security.ArchivaSecurityException;
60 import org.apache.archiva.xml.XMLException;
61 import org.apache.commons.collections.CollectionUtils;
62 import org.apache.commons.io.IOUtils;
63 import org.apache.commons.lang.StringUtils;
64 import org.springframework.stereotype.Service;
66 import javax.inject.Inject;
67 import javax.inject.Named;
68 import javax.ws.rs.core.Response;
69 import java.io.IOException;
70 import java.io.InputStream;
71 import java.nio.charset.Charset;
72 import java.nio.file.Files;
73 import java.nio.file.Path;
74 import java.util.ArrayList;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.Enumeration;
78 import java.util.HashMap;
79 import java.util.LinkedHashSet;
80 import java.util.List;
83 import java.util.jar.JarEntry;
84 import java.util.jar.JarFile;
85 import java.util.zip.ZipEntry;
88 * @author Olivier Lamy
91 @Service( "browseService#rest" )
92 public class DefaultBrowseService
93 extends AbstractRestService
94 implements BrowseService
97 private Charset ARTIFACT_CONTENT_ENCODING=Charset.forName( "UTF-8" );
100 private DependencyTreeBuilder dependencyTreeBuilder;
103 @Named( value = "repositoryProxyConnectors#default" )
104 private RepositoryProxyConnectors connectors;
107 @Named( value = "browse#versionMetadata" )
108 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
110 private ManagedRepositoryContent getManagedRepositoryContent(String id) throws RepositoryException
112 org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
114 throw new RepositoryException( "Could not find repository "+id );
116 return repo.getContent();
120 public BrowseResult getRootGroups( String repositoryId )
121 throws ArchivaRestServiceException
123 List<String> selectedRepos = getSelectedRepos( repositoryId );
125 Set<String> namespaces = new LinkedHashSet<String>();
127 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
128 // it is located here to avoid the content repository implementation needing to do too much for what
129 // is essentially presentation code
130 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
131 RepositorySession repositorySession = repositorySessionFactory.createSession();
134 MetadataResolver metadataResolver = repositorySession.getResolver();
136 for ( String repoId : selectedRepos )
138 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
140 for ( String n : namespacesToCollapse )
142 // TODO: check performance of this
143 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
146 catch ( MetadataResolutionException e )
148 throw new ArchivaRestServiceException( e.getMessage(),
149 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
153 repositorySession.close();
156 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
157 for ( String namespace : namespaces )
159 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
162 Collections.sort( browseGroupResultEntries );
163 return new BrowseResult( browseGroupResultEntries );
167 public BrowseResult browseGroupId( String groupId, String repositoryId )
168 throws ArchivaRestServiceException
170 List<String> selectedRepos = getSelectedRepos( repositoryId );
172 Set<String> projects = new LinkedHashSet<>();
174 RepositorySession repositorySession = repositorySessionFactory.createSession();
175 Set<String> namespaces;
178 MetadataResolver metadataResolver = repositorySession.getResolver();
180 Set<String> namespacesToCollapse = new LinkedHashSet<>();
181 for ( String repoId : selectedRepos )
183 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
185 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
188 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
189 // it is located here to avoid the content repository implementation needing to do too much for what
190 // is essentially presentation code
191 namespaces = new LinkedHashSet<>();
192 for ( String n : namespacesToCollapse )
194 // TODO: check performance of this
196 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
199 catch ( MetadataResolutionException e )
201 throw new ArchivaRestServiceException( e.getMessage(),
202 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
206 repositorySession.close();
208 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
209 for ( String namespace : namespaces )
211 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
213 for ( String project : projects )
215 browseGroupResultEntries.add(
216 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
218 Collections.sort( browseGroupResultEntries );
219 return new BrowseResult( browseGroupResultEntries );
224 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
225 throws ArchivaRestServiceException
227 List<String> selectedRepos = getSelectedRepos( repositoryId );
231 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
232 return new VersionsList( new ArrayList<>( versions ) );
234 catch ( MetadataResolutionException e )
236 throw new ArchivaRestServiceException( e.getMessage(),
237 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
242 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
243 throws MetadataResolutionException
246 RepositorySession repositorySession = repositorySessionFactory.createSession();
249 MetadataResolver metadataResolver = repositorySession.getResolver();
251 Set<String> versions = new LinkedHashSet<String>();
253 for ( String repoId : selectedRepos )
255 Collection<String> projectVersions =
256 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
257 versions.addAll( projectVersions );
260 List<String> sortedVersions = new ArrayList<>( versions );
262 Collections.sort( sortedVersions, VersionComparator.getInstance() );
264 return sortedVersions;
268 repositorySession.close();
273 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
274 String repositoryId )
275 throws ArchivaRestServiceException
277 List<String> selectedRepos = getSelectedRepos( repositoryId );
279 RepositorySession repositorySession = null;
282 repositorySession = repositorySessionFactory.createSession();
284 MetadataResolver metadataResolver = repositorySession.getResolver();
286 ProjectVersionMetadata versionMetadata = null;
287 for ( String repoId : selectedRepos )
289 if ( versionMetadata == null || versionMetadata.isIncomplete() )
293 ProjectVersionMetadata versionMetadataTmp =
294 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
297 if ( versionMetadata == null && versionMetadataTmp != null )
299 versionMetadata = versionMetadataTmp;
304 catch ( MetadataResolutionException e )
306 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
307 groupId, artifactId, repoId, e.getMessage() );
312 return versionMetadata;
316 if ( repositorySession != null )
318 repositorySession.close();
325 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
326 throws ArchivaRestServiceException
329 List<String> selectedRepos = getSelectedRepos( repositoryId );
331 RepositorySession repositorySession = null;
335 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
337 repositorySession = repositorySessionFactory.createSession();
339 MetadataResolver metadataResolver = repositorySession.getResolver();
341 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
343 MavenProjectFacet mavenFacet = new MavenProjectFacet();
344 mavenFacet.setGroupId( groupId );
345 mavenFacet.setArtifactId( artifactId );
346 sharedModel.addFacet( mavenFacet );
348 boolean isFirstVersion = true;
350 for ( String version : projectVersions )
352 ProjectVersionMetadata versionMetadata = null;
353 for ( String repoId : selectedRepos )
355 if ( versionMetadata == null || versionMetadata.isIncomplete() )
359 ProjectVersionMetadata projectVersionMetadataResolved = null;
360 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
361 String cacheKey = null;
362 boolean cacheToUpdate = false;
363 // FIXME a bit maven centric!!!
364 // not a snapshot so get it from cache
367 cacheKey = repoId + groupId + artifactId + version;
368 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
370 if ( useCache && projectVersionMetadataResolved != null )
372 versionMetadata = projectVersionMetadataResolved;
376 projectVersionMetadataResolved =
377 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
378 artifactId, version );
379 versionMetadata = projectVersionMetadataResolved;
380 cacheToUpdate = true;
383 if ( useCache && cacheToUpdate )
385 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
389 catch ( MetadataResolutionException e )
391 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
392 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
397 if ( versionMetadata == null )
402 if ( isFirstVersion )
404 sharedModel = versionMetadata;
405 sharedModel.setId( null );
409 MavenProjectFacet versionMetadataMavenFacet =
410 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
411 if ( versionMetadataMavenFacet != null )
413 if ( mavenFacet.getPackaging() != null //
414 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
415 versionMetadataMavenFacet.getPackaging() ) )
417 mavenFacet.setPackaging( null );
421 if ( StringUtils.isEmpty( sharedModel.getName() ) //
422 && !StringUtils.isEmpty( versionMetadata.getName() ) )
424 sharedModel.setName( versionMetadata.getName() );
427 if ( sharedModel.getDescription() != null //
428 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
429 versionMetadata.getDescription() ) )
431 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
432 ? versionMetadata.getDescription()
436 if ( sharedModel.getIssueManagement() != null //
437 && versionMetadata.getIssueManagement() != null //
438 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
439 versionMetadata.getIssueManagement().getUrl() ) )
441 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
444 if ( sharedModel.getCiManagement() != null //
445 && versionMetadata.getCiManagement() != null //
446 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
447 versionMetadata.getCiManagement().getUrl() ) )
449 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
452 if ( sharedModel.getOrganization() != null //
453 && versionMetadata.getOrganization() != null //
454 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
455 versionMetadata.getOrganization().getName() ) )
457 sharedModel.setOrganization( versionMetadata.getOrganization() );
460 if ( sharedModel.getUrl() != null //
461 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
463 sharedModel.setUrl( versionMetadata.getUrl() );
467 isFirstVersion = false;
471 catch ( MetadataResolutionException e )
473 throw new ArchivaRestServiceException( e.getMessage(),
474 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
478 if ( repositorySession != null )
480 repositorySession.close();
486 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
487 throws ArchivaRestServiceException
489 List<String> selectedRepos = getSelectedRepos( repositoryId );
493 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
495 catch ( Exception e )
497 log.error( e.getMessage(), e );
500 return Collections.emptyList();
504 public List<ManagedRepository> getUserRepositories()
505 throws ArchivaRestServiceException
509 return userRepositories.getAccessibleRepositories( getPrincipal() );
511 catch ( ArchivaSecurityException e )
513 throw new ArchivaRestServiceException( "repositories.read.observable.error",
514 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
519 public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
522 return userRepositories.getManagableRepositories( getPrincipal() );
524 catch ( ArchivaSecurityException e )
526 throw new ArchivaRestServiceException( "repositories.read.managable.error",
527 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
532 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
533 throws ArchivaRestServiceException
535 List<ProjectVersionReference> references = new ArrayList<>();
536 // TODO: what if we get duplicates across repositories?
537 RepositorySession repositorySession = repositorySessionFactory.createSession();
540 MetadataResolver metadataResolver = repositorySession.getResolver();
541 for ( String repoId : getObservableRepos() )
543 // TODO: what about if we want to see this irrespective of version?
545 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
549 catch ( MetadataResolutionException e )
551 throw new ArchivaRestServiceException( e.getMessage(),
552 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
556 repositorySession.close();
559 List<Artifact> artifacts = new ArrayList<>( references.size() );
561 for ( ProjectVersionReference projectVersionReference : references )
563 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
564 projectVersionReference.getProjectVersion() ) );
570 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
571 throws ArchivaRestServiceException
573 ProjectVersionMetadata projectVersionMetadata =
574 getProjectMetadata( groupId, artifactId, version, repositoryId );
575 if ( projectVersionMetadata == null )
577 return Collections.emptyList();
579 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
581 if ( metadataFacet == null )
583 return Collections.emptyList();
585 Map<String, String> map = metadataFacet.toProperties();
586 List<Entry> entries = new ArrayList<>( map.size() );
588 for ( Map.Entry<String, String> entry : map.entrySet() )
590 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
597 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
598 String repositoryId )
599 throws ArchivaRestServiceException
601 ProjectVersionMetadata projectVersionMetadata =
602 getProjectMetadata( groupId, artifactId, version, repositoryId );
604 if ( projectVersionMetadata == null )
606 return Boolean.FALSE;
609 Map<String, String> properties = new HashMap<>();
611 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
613 if ( metadataFacet != null && metadataFacet.toProperties() != null )
615 properties.putAll( metadataFacet.toProperties() );
619 metadataFacet = new GenericMetadataFacet();
622 properties.put( key, value );
624 metadataFacet.fromProperties( properties );
626 projectVersionMetadata.addFacet( metadataFacet );
628 RepositorySession repositorySession = repositorySessionFactory.createSession();
632 MetadataRepository metadataRepository = repositorySession.getRepository();
634 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
636 repositorySession.save();
638 catch ( MetadataRepositoryException e )
640 log.error( e.getMessage(), e );
641 throw new ArchivaRestServiceException( e.getMessage(),
642 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
646 repositorySession.close();
652 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
653 throws ArchivaRestServiceException
655 ProjectVersionMetadata projectVersionMetadata =
656 getProjectMetadata( groupId, artifactId, version, repositoryId );
658 if ( projectVersionMetadata == null )
660 return Boolean.FALSE;
663 GenericMetadataFacet metadataFacet =
664 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
666 if ( metadataFacet != null && metadataFacet.toProperties() != null )
668 Map<String, String> properties = metadataFacet.toProperties();
669 properties.remove( key );
670 metadataFacet.setAdditionalProperties( properties );
677 RepositorySession repositorySession = repositorySessionFactory.createSession();
681 MetadataRepository metadataRepository = repositorySession.getRepository();
683 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
685 repositorySession.save();
687 catch ( MetadataRepositoryException e )
689 log.error( e.getMessage(), e );
690 throw new ArchivaRestServiceException( e.getMessage(),
691 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
695 repositorySession.close();
701 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
702 String classifier, String type, String path,
703 String repositoryId )
704 throws ArchivaRestServiceException
706 List<String> selectedRepos = getSelectedRepos( repositoryId );
709 for ( String repoId : selectedRepos )
712 ManagedRepositoryContent managedRepositoryContent =
713 getManagedRepositoryContent( repoId );
714 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
715 StringUtils.isEmpty( type ) ? "jar" : type,
717 Path file = managedRepositoryContent.toFile( archivaArtifact );
718 if ( Files.exists(file) )
720 return readFileEntries( file, path, repoId );
724 catch ( IOException e )
726 log.error( e.getMessage(), e );
727 throw new ArchivaRestServiceException( e.getMessage(),
728 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
730 catch ( RepositoryNotFoundException e )
732 log.error( e.getMessage(), e );
733 throw new ArchivaRestServiceException( e.getMessage(),
734 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
736 catch ( RepositoryException e )
738 log.error( e.getMessage(), e );
739 throw new ArchivaRestServiceException( e.getMessage(),
740 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
742 return Collections.emptyList();
746 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
747 String repositoryId )
748 throws ArchivaRestServiceException
750 List<String> selectedRepos = getSelectedRepos( repositoryId );
752 List<Artifact> artifactDownloadInfos = new ArrayList<>();
754 try (RepositorySession session = repositorySessionFactory.createSession())
756 MetadataResolver metadataResolver = session.getResolver();
757 for ( String repoId : selectedRepos )
759 List<ArtifactMetadata> artifacts = new ArrayList<>(
760 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
761 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
762 if ( artifacts != null && !artifacts.isEmpty() )
764 return buildArtifacts( artifacts, repoId );
768 catch ( MetadataResolutionException e )
770 log.error( e.getMessage(), e );
771 throw new ArchivaRestServiceException( e.getMessage(),
772 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
775 return artifactDownloadInfos;
779 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
780 String type, String path, String repositoryId )
781 throws ArchivaRestServiceException
783 List<String> selectedRepos = getSelectedRepos( repositoryId );
786 for ( String repoId : selectedRepos )
789 ManagedRepositoryContent managedRepositoryContent = null;
792 managedRepositoryContent = getManagedRepositoryContent( repoId );
794 catch ( RepositoryException e )
796 log.error("No repository content found for "+repoId);
799 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
800 StringUtils.isEmpty( type ) ? "jar" : type,
802 Path file = managedRepositoryContent.toFile( archivaArtifact );
803 if ( !Files.exists(file) )
805 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
808 if ( StringUtils.isNotBlank( path ) )
810 // zip entry of the path -> path must a real file entry of the archive
811 JarFile jarFile = new JarFile( file.toFile() );
812 ZipEntry zipEntry = jarFile.getEntry( path );
813 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
815 return new ArtifactContent( IOUtils.toString( inputStream, ARTIFACT_CONTENT_ENCODING ), repoId );
819 closeQuietly( jarFile );
822 return new ArtifactContent( new String(Files.readAllBytes( file ), ARTIFACT_CONTENT_ENCODING), repoId );
825 catch ( IOException e )
827 log.error( e.getMessage(), e );
828 throw new ArchivaRestServiceException( e.getMessage(),
829 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
831 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
833 return new ArtifactContent();
837 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
838 String repositoryId )
839 throws ArchivaRestServiceException
841 List<String> selectedRepos = getSelectedRepos( repositoryId );
843 boolean snapshot = VersionUtil.isSnapshot( version );
847 for ( String repoId : selectedRepos )
850 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
852 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
853 && managedRepository.isSnapshots() ) )
857 ManagedRepositoryContent managedRepositoryContent = getManagedRepositoryContent( repoId );
859 // FIXME default to jar which can be wrong for war zip etc....
860 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
861 StringUtils.isEmpty( classifier )
863 : classifier, "jar", repoId );
864 Path file = managedRepositoryContent.toFile( archivaArtifact );
866 if ( file != null && Files.exists(file) )
871 // in case of SNAPSHOT we can have timestamped version locally !
872 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
874 Path metadataFile = file.getParent().resolve(MetadataTools.MAVEN_METADATA );
875 if ( Files.exists(metadataFile) )
879 ArchivaRepositoryMetadata archivaRepositoryMetadata =
880 MavenMetadataReader.read( metadataFile );
881 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
882 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
883 // rebuild file name with timestamped version and build number
884 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
885 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
886 .append( '-' ).append( timeStamp ) //
887 .append( '-' ).append( Integer.toString( buildNumber ) ) //
888 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
889 .append( ".jar" ).toString();
891 Path timeStampFile = file.getParent().resolve( timeStampFileName );
892 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.toAbsolutePath() );
893 if ( Files.exists(timeStampFile) )
898 catch ( XMLException e )
900 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
905 String path = managedRepositoryContent.toPath( archivaArtifact );
907 file = connectors.fetchFromProxies( managedRepositoryContent, path );
909 if ( file != null && Files.exists(file) )
912 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
913 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
918 catch ( RepositoryAdminException e )
920 log.error( e.getMessage(), e );
921 throw new ArchivaRestServiceException( e.getMessage(),
922 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
924 catch ( RepositoryException e )
926 log.error( e.getMessage(), e );
927 throw new ArchivaRestServiceException( e.getMessage(),
928 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
935 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
936 throws ArchivaRestServiceException
938 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
942 public List<Artifact> getArtifacts( String repositoryId )
943 throws ArchivaRestServiceException
945 RepositorySession repositorySession = repositorySessionFactory.createSession();
948 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
949 return buildArtifacts( artifactMetadatas, repositoryId );
951 catch ( MetadataRepositoryException e )
953 throw new ArchivaRestServiceException( e.getMessage(), e );
957 repositorySession.close();
962 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
963 throws ArchivaRestServiceException
965 RepositorySession repositorySession = repositorySessionFactory.createSession();
968 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionMetadata( key, value, repositoryId );
969 return buildArtifacts( artifactMetadatas, repositoryId );
971 catch ( MetadataRepositoryException e )
973 throw new ArchivaRestServiceException( e.getMessage(), e );
977 repositorySession.close();
982 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
983 throws ArchivaRestServiceException
985 RepositorySession repositorySession = repositorySessionFactory.createSession();
988 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata( key, value, repositoryId );
989 return buildArtifacts( artifactMetadatas, repositoryId );
991 catch ( MetadataRepositoryException e )
993 throw new ArchivaRestServiceException( e.getMessage(), e );
997 repositorySession.close();
1002 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
1003 throws ArchivaRestServiceException
1005 RepositorySession repositorySession = repositorySessionFactory.createSession();
1008 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty( key, value, repositoryId );
1009 return buildArtifacts( artifactMetadatas, repositoryId );
1011 catch ( MetadataRepositoryException e )
1013 throw new ArchivaRestServiceException( e.getMessage(), e );
1017 repositorySession.close();
1022 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1023 throws ArchivaRestServiceException
1025 boolean result = true;
1026 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1028 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1029 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1040 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1041 throws ArchivaRestServiceException
1043 RepositorySession repositorySession = repositorySessionFactory.createSession();
1046 List<ArtifactMetadata> artifactMetadatas =
1047 repositorySession.getRepository().searchArtifacts( text, repositoryId, exact == null ? false : exact );
1048 return buildArtifacts( artifactMetadatas, repositoryId );
1050 catch ( MetadataRepositoryException e )
1052 throw new ArchivaRestServiceException( e.getMessage(), e );
1056 repositorySession.close();
1061 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1062 throws ArchivaRestServiceException
1064 RepositorySession repositorySession = repositorySessionFactory.createSession();
1067 List<ArtifactMetadata> artifactMetadatas =
1068 repositorySession.getRepository().searchArtifacts( key, text, repositoryId, exact == null ? false : exact );
1069 return buildArtifacts( artifactMetadatas, repositoryId );
1071 catch ( MetadataRepositoryException e )
1073 throw new ArchivaRestServiceException( e.getMessage(), e );
1077 repositorySession.close();
1081 //---------------------------
1083 //---------------------------
1085 private void closeQuietly( JarFile jarFile )
1087 if ( jarFile != null )
1093 catch ( IOException e )
1095 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1100 protected List<ArtifactContentEntry> readFileEntries(final Path file, final String filterPath, final String repoId )
1103 String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
1104 StringUtils.substringAfter(filterPath, "/") : filterPath);
1105 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1106 int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
1107 if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
1110 JarFile jarFile = new JarFile( file.toFile() );
1113 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1114 while ( jarEntryEnumeration.hasMoreElements() )
1116 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1117 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
1118 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1119 String entryRootPath = getRootPath( cleanedEntryName );
1120 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1121 if ( StringUtils.isEmpty( cleanedfilterPath ) //
1122 && !artifactContentEntryMap.containsKey( entryRootPath ) //
1123 && depth == filterDepth )
1126 artifactContentEntryMap.put( entryRootPath,
1127 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1132 if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath ) //
1133 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1135 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1136 !currentEntry.isDirectory(),
1142 if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
1144 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1146 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1148 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1151 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1152 if ( sorted == null )
1154 return Collections.emptyList();
1156 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1162 if ( jarFile != null )
1167 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1168 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1172 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1174 int smallestDepth = Integer.MAX_VALUE;
1175 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1176 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1179 ArtifactContentEntry current = entry.getValue();
1181 if ( current.getDepth() < smallestDepth )
1183 smallestDepth = current.getDepth();
1186 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1188 if ( currentList == null )
1190 currentList = new ArrayList<>();
1191 currentList.add( current );
1192 perDepthList.put( current.getDepth(), currentList );
1196 currentList.add( current );
1201 return perDepthList.get( smallestDepth );
1206 * @return org/apache -> org , org -> org
1208 private String getRootPath( String path )
1210 if ( StringUtils.contains( path, '/' ) )
1212 return StringUtils.substringBefore( path, "/" );
1217 private List<String> getSelectedRepos( String repositoryId )
1218 throws ArchivaRestServiceException
1221 List<String> selectedRepos = getObservableRepos();
1223 if ( CollectionUtils.isEmpty( selectedRepos ) )
1225 return Collections.emptyList();
1228 if ( StringUtils.isNotEmpty( repositoryId ) )
1230 // check user has karma on the repository
1231 if ( !selectedRepos.contains( repositoryId ) )
1233 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1234 Response.Status.FORBIDDEN.getStatusCode(), null );
1236 selectedRepos = Collections.singletonList( repositoryId );
1238 return selectedRepos;
1242 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1243 Collection<String> repoIds, String n )
1244 throws MetadataResolutionException
1246 Set<String> subNamespaces = new LinkedHashSet<String>();
1247 for ( String repoId : repoIds )
1249 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1251 if ( subNamespaces.size() != 1 )
1253 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1258 for ( String repoId : repoIds )
1260 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1261 if ( projects != null && !projects.isEmpty() )
1263 log.debug( "{} is not collapsible as it has projects", n );
1267 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1268 n + "." + subNamespaces.iterator().next() );
1272 public Cache getVersionMetadataCache()
1274 return versionMetadataCache;
1277 public void setVersionMetadataCache( Cache versionMetadataCache )
1279 this.versionMetadataCache = versionMetadataCache;