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.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
98 private DependencyTreeBuilder dependencyTreeBuilder;
101 private RepositoryContentFactory repositoryContentFactory;
104 @Named( value = "repositoryProxyConnectors#default" )
105 private RepositoryProxyConnectors connectors;
108 @Named( value = "browse#versionMetadata" )
109 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
112 public BrowseResult getRootGroups( String repositoryId )
113 throws ArchivaRestServiceException
115 List<String> selectedRepos = getSelectedRepos( repositoryId );
117 Set<String> namespaces = new LinkedHashSet<String>();
119 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
120 // it is located here to avoid the content repository implementation needing to do too much for what
121 // is essentially presentation code
122 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
123 RepositorySession repositorySession = repositorySessionFactory.createSession();
126 MetadataResolver metadataResolver = repositorySession.getResolver();
128 for ( String repoId : selectedRepos )
130 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
132 for ( String n : namespacesToCollapse )
134 // TODO: check performance of this
135 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
138 catch ( MetadataResolutionException e )
140 throw new ArchivaRestServiceException( e.getMessage(),
141 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
145 repositorySession.close();
148 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
149 for ( String namespace : namespaces )
151 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
154 Collections.sort( browseGroupResultEntries );
155 return new BrowseResult( browseGroupResultEntries );
159 public BrowseResult browseGroupId( String groupId, String repositoryId )
160 throws ArchivaRestServiceException
162 List<String> selectedRepos = getSelectedRepos( repositoryId );
164 Set<String> projects = new LinkedHashSet<>();
166 RepositorySession repositorySession = repositorySessionFactory.createSession();
167 Set<String> namespaces;
170 MetadataResolver metadataResolver = repositorySession.getResolver();
172 Set<String> namespacesToCollapse = new LinkedHashSet<>();
173 for ( String repoId : selectedRepos )
175 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
177 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
180 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
181 // it is located here to avoid the content repository implementation needing to do too much for what
182 // is essentially presentation code
183 namespaces = new LinkedHashSet<>();
184 for ( String n : namespacesToCollapse )
186 // TODO: check performance of this
188 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
191 catch ( MetadataResolutionException e )
193 throw new ArchivaRestServiceException( e.getMessage(),
194 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
198 repositorySession.close();
200 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
201 for ( String namespace : namespaces )
203 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
205 for ( String project : projects )
207 browseGroupResultEntries.add(
208 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
210 Collections.sort( browseGroupResultEntries );
211 return new BrowseResult( browseGroupResultEntries );
216 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
217 throws ArchivaRestServiceException
219 List<String> selectedRepos = getSelectedRepos( repositoryId );
223 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
224 return new VersionsList( new ArrayList<>( versions ) );
226 catch ( MetadataResolutionException e )
228 throw new ArchivaRestServiceException( e.getMessage(),
229 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
234 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
235 throws MetadataResolutionException
238 RepositorySession repositorySession = repositorySessionFactory.createSession();
241 MetadataResolver metadataResolver = repositorySession.getResolver();
243 Set<String> versions = new LinkedHashSet<String>();
245 for ( String repoId : selectedRepos )
247 Collection<String> projectVersions =
248 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
249 versions.addAll( projectVersions );
252 List<String> sortedVersions = new ArrayList<>( versions );
254 Collections.sort( sortedVersions, VersionComparator.getInstance() );
256 return sortedVersions;
260 repositorySession.close();
265 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
266 String repositoryId )
267 throws ArchivaRestServiceException
269 List<String> selectedRepos = getSelectedRepos( repositoryId );
271 RepositorySession repositorySession = null;
274 repositorySession = repositorySessionFactory.createSession();
276 MetadataResolver metadataResolver = repositorySession.getResolver();
278 ProjectVersionMetadata versionMetadata = null;
279 for ( String repoId : selectedRepos )
281 if ( versionMetadata == null || versionMetadata.isIncomplete() )
285 ProjectVersionMetadata versionMetadataTmp =
286 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
289 if ( versionMetadata == null && versionMetadataTmp != null )
291 versionMetadata = versionMetadataTmp;
296 catch ( MetadataResolutionException e )
298 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
299 groupId, artifactId, repoId, e.getMessage() );
304 return versionMetadata;
308 if ( repositorySession != null )
310 repositorySession.close();
317 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
318 throws ArchivaRestServiceException
321 List<String> selectedRepos = getSelectedRepos( repositoryId );
323 RepositorySession repositorySession = null;
327 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
329 repositorySession = repositorySessionFactory.createSession();
331 MetadataResolver metadataResolver = repositorySession.getResolver();
333 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
335 MavenProjectFacet mavenFacet = new MavenProjectFacet();
336 mavenFacet.setGroupId( groupId );
337 mavenFacet.setArtifactId( artifactId );
338 sharedModel.addFacet( mavenFacet );
340 boolean isFirstVersion = true;
342 for ( String version : projectVersions )
344 ProjectVersionMetadata versionMetadata = null;
345 for ( String repoId : selectedRepos )
347 if ( versionMetadata == null || versionMetadata.isIncomplete() )
351 ProjectVersionMetadata projectVersionMetadataResolved = null;
352 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
353 String cacheKey = null;
354 boolean cacheToUpdate = false;
355 // FIXME a bit maven centric!!!
356 // not a snapshot so get it from cache
359 cacheKey = repoId + groupId + artifactId + version;
360 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
362 if ( useCache && projectVersionMetadataResolved != null )
364 versionMetadata = projectVersionMetadataResolved;
368 projectVersionMetadataResolved =
369 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
370 artifactId, version );
371 versionMetadata = projectVersionMetadataResolved;
372 cacheToUpdate = true;
375 if ( useCache && cacheToUpdate )
377 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
381 catch ( MetadataResolutionException e )
383 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
384 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
389 if ( versionMetadata == null )
394 if ( isFirstVersion )
396 sharedModel = versionMetadata;
397 sharedModel.setId( null );
401 MavenProjectFacet versionMetadataMavenFacet =
402 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
403 if ( versionMetadataMavenFacet != null )
405 if ( mavenFacet.getPackaging() != null //
406 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
407 versionMetadataMavenFacet.getPackaging() ) )
409 mavenFacet.setPackaging( null );
413 if ( StringUtils.isEmpty( sharedModel.getName() ) //
414 && !StringUtils.isEmpty( versionMetadata.getName() ) )
416 sharedModel.setName( versionMetadata.getName() );
419 if ( sharedModel.getDescription() != null //
420 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
421 versionMetadata.getDescription() ) )
423 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
424 ? versionMetadata.getDescription()
428 if ( sharedModel.getIssueManagement() != null //
429 && versionMetadata.getIssueManagement() != null //
430 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
431 versionMetadata.getIssueManagement().getUrl() ) )
433 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
436 if ( sharedModel.getCiManagement() != null //
437 && versionMetadata.getCiManagement() != null //
438 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
439 versionMetadata.getCiManagement().getUrl() ) )
441 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
444 if ( sharedModel.getOrganization() != null //
445 && versionMetadata.getOrganization() != null //
446 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
447 versionMetadata.getOrganization().getName() ) )
449 sharedModel.setOrganization( versionMetadata.getOrganization() );
452 if ( sharedModel.getUrl() != null //
453 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
455 sharedModel.setUrl( versionMetadata.getUrl() );
459 isFirstVersion = false;
463 catch ( MetadataResolutionException e )
465 throw new ArchivaRestServiceException( e.getMessage(),
466 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
470 if ( repositorySession != null )
472 repositorySession.close();
478 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
479 throws ArchivaRestServiceException
481 List<String> selectedRepos = getSelectedRepos( repositoryId );
485 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
487 catch ( Exception e )
489 log.error( e.getMessage(), e );
492 return Collections.emptyList();
496 public List<ManagedRepository> getUserRepositories()
497 throws ArchivaRestServiceException
501 return userRepositories.getAccessibleRepositories( getPrincipal() );
503 catch ( ArchivaSecurityException e )
505 throw new ArchivaRestServiceException( "repositories.read.observable.error",
506 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
511 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
512 throws ArchivaRestServiceException
514 List<ProjectVersionReference> references = new ArrayList<>();
515 // TODO: what if we get duplicates across repositories?
516 RepositorySession repositorySession = repositorySessionFactory.createSession();
519 MetadataResolver metadataResolver = repositorySession.getResolver();
520 for ( String repoId : getObservableRepos() )
522 // TODO: what about if we want to see this irrespective of version?
524 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
528 catch ( MetadataResolutionException e )
530 throw new ArchivaRestServiceException( e.getMessage(),
531 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
535 repositorySession.close();
538 List<Artifact> artifacts = new ArrayList<>( references.size() );
540 for ( ProjectVersionReference projectVersionReference : references )
542 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
543 projectVersionReference.getProjectVersion() ) );
549 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
550 throws ArchivaRestServiceException
552 ProjectVersionMetadata projectVersionMetadata =
553 getProjectMetadata( groupId, artifactId, version, repositoryId );
554 if ( projectVersionMetadata == null )
556 return Collections.emptyList();
558 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
560 if ( metadataFacet == null )
562 return Collections.emptyList();
564 Map<String, String> map = metadataFacet.toProperties();
565 List<Entry> entries = new ArrayList<>( map.size() );
567 for ( Map.Entry<String, String> entry : map.entrySet() )
569 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
576 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
577 String repositoryId )
578 throws ArchivaRestServiceException
580 ProjectVersionMetadata projectVersionMetadata =
581 getProjectMetadata( groupId, artifactId, version, repositoryId );
583 if ( projectVersionMetadata == null )
585 return Boolean.FALSE;
588 Map<String, String> properties = new HashMap<>();
590 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
592 if ( metadataFacet != null && metadataFacet.toProperties() != null )
594 properties.putAll( metadataFacet.toProperties() );
598 metadataFacet = new GenericMetadataFacet();
601 properties.put( key, value );
603 metadataFacet.fromProperties( properties );
605 projectVersionMetadata.addFacet( metadataFacet );
607 RepositorySession repositorySession = repositorySessionFactory.createSession();
611 MetadataRepository metadataRepository = repositorySession.getRepository();
613 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
615 repositorySession.save();
617 catch ( MetadataRepositoryException e )
619 log.error( e.getMessage(), e );
620 throw new ArchivaRestServiceException( e.getMessage(),
621 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
625 repositorySession.close();
631 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
632 throws ArchivaRestServiceException
634 ProjectVersionMetadata projectVersionMetadata =
635 getProjectMetadata( groupId, artifactId, version, repositoryId );
637 if ( projectVersionMetadata == null )
639 return Boolean.FALSE;
642 GenericMetadataFacet metadataFacet =
643 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
645 if ( metadataFacet != null && metadataFacet.toProperties() != null )
647 Map<String, String> properties = metadataFacet.toProperties();
648 properties.remove( key );
649 metadataFacet.setAdditionalProperties( properties );
656 RepositorySession repositorySession = repositorySessionFactory.createSession();
660 MetadataRepository metadataRepository = repositorySession.getRepository();
662 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
664 repositorySession.save();
666 catch ( MetadataRepositoryException e )
668 log.error( e.getMessage(), e );
669 throw new ArchivaRestServiceException( e.getMessage(),
670 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
674 repositorySession.close();
680 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
681 String classifier, String type, String path,
682 String repositoryId )
683 throws ArchivaRestServiceException
685 List<String> selectedRepos = getSelectedRepos( repositoryId );
688 for ( String repoId : selectedRepos )
691 ManagedRepositoryContent managedRepositoryContent =
692 repositoryContentFactory.getManagedRepositoryContent( repoId );
693 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
694 StringUtils.isEmpty( type ) ? "jar" : type,
696 File file = managedRepositoryContent.toFile( archivaArtifact );
699 return readFileEntries( file, path, repoId );
703 catch ( IOException e )
705 log.error( e.getMessage(), e );
706 throw new ArchivaRestServiceException( e.getMessage(),
707 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
709 catch ( RepositoryNotFoundException e )
711 log.error( e.getMessage(), e );
712 throw new ArchivaRestServiceException( e.getMessage(),
713 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
715 catch ( RepositoryException e )
717 log.error( e.getMessage(), e );
718 throw new ArchivaRestServiceException( e.getMessage(),
719 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
721 return Collections.emptyList();
725 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
726 String repositoryId )
727 throws ArchivaRestServiceException
729 List<String> selectedRepos = getSelectedRepos( repositoryId );
731 List<Artifact> artifactDownloadInfos = new ArrayList<>();
733 try (RepositorySession session = repositorySessionFactory.createSession())
735 MetadataResolver metadataResolver = session.getResolver();
736 for ( String repoId : selectedRepos )
738 List<ArtifactMetadata> artifacts = new ArrayList<>(
739 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
740 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
741 if ( artifacts != null && !artifacts.isEmpty() )
743 return buildArtifacts( artifacts, repoId );
747 catch ( MetadataResolutionException e )
749 log.error( e.getMessage(), e );
750 throw new ArchivaRestServiceException( e.getMessage(),
751 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
754 return artifactDownloadInfos;
758 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
759 String type, String path, String repositoryId )
760 throws ArchivaRestServiceException
762 List<String> selectedRepos = getSelectedRepos( repositoryId );
765 for ( String repoId : selectedRepos )
768 ManagedRepositoryContent managedRepositoryContent =
769 repositoryContentFactory.getManagedRepositoryContent( repoId );
770 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
771 StringUtils.isEmpty( type ) ? "jar" : type,
773 File file = managedRepositoryContent.toFile( archivaArtifact );
774 if ( !file.exists() )
776 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
779 if ( StringUtils.isNotBlank( path ) )
781 // zip entry of the path -> path must a real file entry of the archive
782 JarFile jarFile = new JarFile( file );
783 ZipEntry zipEntry = jarFile.getEntry( path );
784 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
786 return new ArtifactContent( IOUtils.toString( inputStream ), repoId );
790 closeQuietly( jarFile );
793 return new ArtifactContent( FileUtils.readFileToString( file ), repoId );
796 catch ( IOException e )
798 log.error( e.getMessage(), e );
799 throw new ArchivaRestServiceException( e.getMessage(),
800 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
802 catch ( RepositoryNotFoundException e )
804 log.error( e.getMessage(), e );
805 throw new ArchivaRestServiceException( e.getMessage(),
806 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
808 catch ( RepositoryException e )
810 log.error( e.getMessage(), e );
811 throw new ArchivaRestServiceException( e.getMessage(),
812 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
814 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
816 return new ArtifactContent();
820 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
821 String repositoryId )
822 throws ArchivaRestServiceException
824 List<String> selectedRepos = getSelectedRepos( repositoryId );
826 boolean snapshot = VersionUtil.isSnapshot( version );
830 for ( String repoId : selectedRepos )
833 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
835 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
836 && managedRepository.isSnapshots() ) )
840 ManagedRepositoryContent managedRepositoryContent =
841 repositoryContentFactory.getManagedRepositoryContent( repoId );
842 // FIXME default to jar which can be wrong for war zip etc....
843 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
844 StringUtils.isEmpty( classifier )
846 : classifier, "jar", repoId );
847 File file = managedRepositoryContent.toFile( archivaArtifact );
849 if ( file != null && file.exists() )
854 // in case of SNAPSHOT we can have timestamped version locally !
855 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
857 File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA );
858 if ( metadataFile.exists() )
862 ArchivaRepositoryMetadata archivaRepositoryMetadata =
863 MavenMetadataReader.read( metadataFile );
864 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
865 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
866 // rebuild file name with timestamped version and build number
867 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
868 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
869 .append( '-' ).append( timeStamp ) //
870 .append( '-' ).append( Integer.toString( buildNumber ) ) //
871 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
872 .append( ".jar" ).toString();
874 File timeStampFile = new File( file.getParent(), timeStampFileName );
875 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
876 if ( timeStampFile.exists() )
881 catch ( XMLException e )
883 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
888 String path = managedRepositoryContent.toPath( archivaArtifact );
890 file = connectors.fetchFromProxies( managedRepositoryContent, path );
892 if ( file != null && file.exists() )
895 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
896 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
901 catch ( RepositoryAdminException e )
903 log.error( e.getMessage(), e );
904 throw new ArchivaRestServiceException( e.getMessage(),
905 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
907 catch ( RepositoryException e )
909 log.error( e.getMessage(), e );
910 throw new ArchivaRestServiceException( e.getMessage(),
911 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
918 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
919 throws ArchivaRestServiceException
921 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
925 public List<Artifact> getArtifacts( String repositoryId )
926 throws ArchivaRestServiceException
928 RepositorySession repositorySession = repositorySessionFactory.createSession();
931 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
932 return buildArtifacts( artifactMetadatas, repositoryId );
934 catch ( MetadataRepositoryException e )
936 throw new ArchivaRestServiceException( e.getMessage(), e );
940 repositorySession.close();
945 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
946 throws ArchivaRestServiceException
948 RepositorySession repositorySession = repositorySessionFactory.createSession();
951 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionMetadata( key, value, repositoryId );
952 return buildArtifacts( artifactMetadatas, repositoryId );
954 catch ( MetadataRepositoryException e )
956 throw new ArchivaRestServiceException( e.getMessage(), e );
960 repositorySession.close();
965 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
966 throws ArchivaRestServiceException
968 RepositorySession repositorySession = repositorySessionFactory.createSession();
971 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata( key, value, repositoryId );
972 return buildArtifacts( artifactMetadatas, repositoryId );
974 catch ( MetadataRepositoryException e )
976 throw new ArchivaRestServiceException( e.getMessage(), e );
980 repositorySession.close();
985 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
986 throws ArchivaRestServiceException
988 RepositorySession repositorySession = repositorySessionFactory.createSession();
991 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty( key, value, repositoryId );
992 return buildArtifacts( artifactMetadatas, repositoryId );
994 catch ( MetadataRepositoryException e )
996 throw new ArchivaRestServiceException( e.getMessage(), e );
1000 repositorySession.close();
1005 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1006 throws ArchivaRestServiceException
1008 boolean result = true;
1009 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1011 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1012 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1023 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1024 throws ArchivaRestServiceException
1026 RepositorySession repositorySession = repositorySessionFactory.createSession();
1029 List<ArtifactMetadata> artifactMetadatas =
1030 repositorySession.getRepository().searchArtifacts( text, repositoryId, exact == null ? false : exact );
1031 return buildArtifacts( artifactMetadatas, repositoryId );
1033 catch ( MetadataRepositoryException e )
1035 throw new ArchivaRestServiceException( e.getMessage(), e );
1039 repositorySession.close();
1044 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1045 throws ArchivaRestServiceException
1047 RepositorySession repositorySession = repositorySessionFactory.createSession();
1050 List<ArtifactMetadata> artifactMetadatas =
1051 repositorySession.getRepository().searchArtifacts( key, text, repositoryId, exact == null ? false : exact );
1052 return buildArtifacts( artifactMetadatas, repositoryId );
1054 catch ( MetadataRepositoryException e )
1056 throw new ArchivaRestServiceException( e.getMessage(), e );
1060 repositorySession.close();
1064 //---------------------------
1066 //---------------------------
1068 private void closeQuietly( JarFile jarFile )
1070 if ( jarFile != null )
1076 catch ( IOException e )
1078 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1083 protected List<ArtifactContentEntry> readFileEntries( File file, String filterPath, String repoId )
1086 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1087 int filterDepth = StringUtils.countMatches( filterPath, "/" );
1088 /*if ( filterDepth == 0 )
1092 JarFile jarFile = new JarFile( file );
1095 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1096 while ( jarEntryEnumeration.hasMoreElements() )
1098 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1099 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
1100 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1101 String entryRootPath = getRootPath( cleanedEntryName );
1102 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1103 if ( StringUtils.isEmpty( filterPath ) //
1104 && !artifactContentEntryMap.containsKey( entryRootPath ) //
1105 && depth == filterDepth )
1108 artifactContentEntryMap.put( entryRootPath,
1109 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1114 if ( StringUtils.startsWith( cleanedEntryName, filterPath ) //
1115 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1117 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1118 !currentEntry.isDirectory(),
1124 if ( StringUtils.isNotEmpty( filterPath ) )
1126 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1128 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1130 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1133 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1134 if ( sorted == null )
1136 return Collections.emptyList();
1138 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1144 if ( jarFile != null )
1149 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1150 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1154 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1156 int smallestDepth = Integer.MAX_VALUE;
1157 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1158 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1161 ArtifactContentEntry current = entry.getValue();
1163 if ( current.getDepth() < smallestDepth )
1165 smallestDepth = current.getDepth();
1168 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1170 if ( currentList == null )
1172 currentList = new ArrayList<>();
1173 currentList.add( current );
1174 perDepthList.put( current.getDepth(), currentList );
1178 currentList.add( current );
1183 return perDepthList.get( smallestDepth );
1188 * @return org/apache -> org , org -> org
1190 private String getRootPath( String path )
1192 if ( StringUtils.contains( path, '/' ) )
1194 return StringUtils.substringBefore( path, "/" );
1199 private List<String> getSelectedRepos( String repositoryId )
1200 throws ArchivaRestServiceException
1203 List<String> selectedRepos = getObservableRepos();
1205 if ( CollectionUtils.isEmpty( selectedRepos ) )
1207 return Collections.emptyList();
1210 if ( StringUtils.isNotEmpty( repositoryId ) )
1212 // check user has karma on the repository
1213 if ( !selectedRepos.contains( repositoryId ) )
1215 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1216 Response.Status.FORBIDDEN.getStatusCode(), null );
1218 selectedRepos = Collections.singletonList( repositoryId );
1220 return selectedRepos;
1224 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1225 Collection<String> repoIds, String n )
1226 throws MetadataResolutionException
1228 Set<String> subNamespaces = new LinkedHashSet<String>();
1229 for ( String repoId : repoIds )
1231 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1233 if ( subNamespaces.size() != 1 )
1235 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1240 for ( String repoId : repoIds )
1242 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1243 if ( projects != null && !projects.isEmpty() )
1245 log.debug( "{} is not collapsible as it has projects", n );
1249 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1250 n + "." + subNamespaces.iterator().next() );
1254 public Cache getVersionMetadataCache()
1256 return versionMetadataCache;
1259 public void setVersionMetadataCache( Cache versionMetadataCache )
1261 this.versionMetadataCache = versionMetadataCache;