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;
111 public BrowseResult getRootGroups( String repositoryId )
112 throws ArchivaRestServiceException
114 List<String> selectedRepos = getSelectedRepos( repositoryId );
116 Set<String> namespaces = new LinkedHashSet<String>();
118 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
119 // it is located here to avoid the content repository implementation needing to do too much for what
120 // is essentially presentation code
121 Set<String> namespacesToCollapse;
122 RepositorySession repositorySession = repositorySessionFactory.createSession();
125 MetadataResolver metadataResolver = repositorySession.getResolver();
126 namespacesToCollapse = new LinkedHashSet<String>();
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<BrowseResultEntry>( namespaces.size() );
149 for ( String namespace : namespaces )
151 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
154 Collections.sort( browseGroupResultEntries );
155 return new BrowseResult( browseGroupResultEntries );
158 public BrowseResult browseGroupId( String groupId, String repositoryId )
159 throws ArchivaRestServiceException
161 List<String> selectedRepos = getSelectedRepos( repositoryId );
163 Set<String> projects = new LinkedHashSet<String>();
165 RepositorySession repositorySession = repositorySessionFactory.createSession();
166 Set<String> namespaces;
169 MetadataResolver metadataResolver = repositorySession.getResolver();
171 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
172 for ( String repoId : selectedRepos )
174 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
176 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
179 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
180 // it is located here to avoid the content repository implementation needing to do too much for what
181 // is essentially presentation code
182 namespaces = new LinkedHashSet<String>();
183 for ( String n : namespacesToCollapse )
185 // TODO: check performance of this
187 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
190 catch ( MetadataResolutionException e )
192 throw new ArchivaRestServiceException( e.getMessage(),
193 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
197 repositorySession.close();
199 List<BrowseResultEntry> browseGroupResultEntries =
200 new ArrayList<BrowseResultEntry>( 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 );
215 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
216 throws ArchivaRestServiceException
218 List<String> selectedRepos = getSelectedRepos( repositoryId );
222 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
223 return new VersionsList( new ArrayList<String>( versions ) );
225 catch ( MetadataResolutionException e )
227 throw new ArchivaRestServiceException( e.getMessage(),
228 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
233 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
234 throws MetadataResolutionException
237 RepositorySession repositorySession = repositorySessionFactory.createSession();
240 MetadataResolver metadataResolver = repositorySession.getResolver();
242 Set<String> versions = new LinkedHashSet<String>();
244 for ( String repoId : selectedRepos )
246 Collection<String> projectVersions =
247 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
248 versions.addAll( projectVersions );
251 List<String> sortedVersions = new ArrayList<String>( versions );
253 Collections.sort( sortedVersions, VersionComparator.getInstance() );
255 return sortedVersions;
259 repositorySession.close();
263 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
264 String repositoryId )
265 throws ArchivaRestServiceException
267 List<String> selectedRepos = getSelectedRepos( repositoryId );
269 RepositorySession repositorySession = null;
272 repositorySession = repositorySessionFactory.createSession();
274 MetadataResolver metadataResolver = repositorySession.getResolver();
276 ProjectVersionMetadata versionMetadata = null;
277 for ( String repoId : selectedRepos )
279 if ( versionMetadata == null || versionMetadata.isIncomplete() )
284 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
287 catch ( MetadataResolutionException e )
289 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
290 groupId, artifactId, repoId, e.getMessage() );
295 return versionMetadata;
299 if ( repositorySession != null )
301 repositorySession.close();
307 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
308 throws ArchivaRestServiceException
311 List<String> selectedRepos = getSelectedRepos( repositoryId );
313 RepositorySession repositorySession = null;
317 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
319 repositorySession = repositorySessionFactory.createSession();
321 MetadataResolver metadataResolver = repositorySession.getResolver();
323 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
325 MavenProjectFacet mavenFacet = new MavenProjectFacet();
326 mavenFacet.setGroupId( groupId );
327 mavenFacet.setArtifactId( artifactId );
328 sharedModel.addFacet( mavenFacet );
330 boolean isFirstVersion = true;
332 for ( String version : projectVersions )
334 ProjectVersionMetadata versionMetadata = null;
335 for ( String repoId : selectedRepos )
337 if ( versionMetadata == null || versionMetadata.isIncomplete() )
341 ProjectVersionMetadata projectVersionMetadataResolved = null;
342 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
343 String cacheKey = null;
344 boolean cacheToUpdate = false;
345 // FIXME a bit maven centric!!!
346 // not a snapshot so get it from cache
349 cacheKey = repoId + groupId + artifactId + version;
350 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
352 if ( useCache && projectVersionMetadataResolved != null )
354 versionMetadata = projectVersionMetadataResolved;
358 projectVersionMetadataResolved =
359 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
360 artifactId, version );
361 versionMetadata = projectVersionMetadataResolved;
362 cacheToUpdate = true;
365 if ( useCache && cacheToUpdate )
367 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
371 catch ( MetadataResolutionException e )
373 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
374 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
379 if ( versionMetadata == null )
384 if ( isFirstVersion )
386 sharedModel = versionMetadata;
387 sharedModel.setId( null );
391 MavenProjectFacet versionMetadataMavenFacet =
392 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
393 if ( versionMetadataMavenFacet != null )
395 if ( mavenFacet.getPackaging() != null //
396 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
397 versionMetadataMavenFacet.getPackaging() ) )
399 mavenFacet.setPackaging( null );
403 if ( StringUtils.isEmpty( sharedModel.getName() ) //
404 && !StringUtils.isEmpty( versionMetadata.getName() ) )
406 sharedModel.setName( versionMetadata.getName() );
409 if ( sharedModel.getDescription() != null //
410 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
411 versionMetadata.getDescription() ) )
413 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
414 ? versionMetadata.getDescription()
418 if ( sharedModel.getIssueManagement() != null //
419 && versionMetadata.getIssueManagement() != null //
420 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
421 versionMetadata.getIssueManagement().getUrl() ) )
423 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
426 if ( sharedModel.getCiManagement() != null //
427 && versionMetadata.getCiManagement() != null //
428 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
429 versionMetadata.getCiManagement().getUrl() ) )
431 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
434 if ( sharedModel.getOrganization() != null //
435 && versionMetadata.getOrganization() != null //
436 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
437 versionMetadata.getOrganization().getName() ) )
439 sharedModel.setOrganization( versionMetadata.getOrganization() );
442 if ( sharedModel.getUrl() != null //
443 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
445 sharedModel.setUrl( versionMetadata.getUrl() );
449 isFirstVersion = false;
453 catch ( MetadataResolutionException e )
455 throw new ArchivaRestServiceException( e.getMessage(),
456 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
460 if ( repositorySession != null )
462 repositorySession.close();
467 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
468 throws ArchivaRestServiceException
470 List<String> selectedRepos = getSelectedRepos( repositoryId );
475 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
478 catch ( Exception e )
480 log.error( e.getMessage(), e );
483 return Collections.emptyList();
486 public List<ManagedRepository> getUserRepositories()
487 throws ArchivaRestServiceException
491 return userRepositories.getAccessibleRepositories( getPrincipal() );
493 catch ( ArchivaSecurityException e )
495 throw new ArchivaRestServiceException( "repositories.read.observable.error",
496 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
500 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
501 throws ArchivaRestServiceException
503 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
504 // TODO: what if we get duplicates across repositories?
505 RepositorySession repositorySession = repositorySessionFactory.createSession();
508 MetadataResolver metadataResolver = repositorySession.getResolver();
509 for ( String repoId : getObservableRepos() )
511 // TODO: what about if we want to see this irrespective of version?
513 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
517 catch ( MetadataResolutionException e )
519 throw new ArchivaRestServiceException( e.getMessage(),
520 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
524 repositorySession.close();
527 List<Artifact> artifacts = new ArrayList<Artifact>( references.size() );
529 for ( ProjectVersionReference projectVersionReference : references )
531 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
532 projectVersionReference.getProjectVersion() ) );
537 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
538 throws ArchivaRestServiceException
540 ProjectVersionMetadata projectVersionMetadata =
541 getProjectMetadata( groupId, artifactId, version, repositoryId );
542 if ( projectVersionMetadata == null )
544 return Collections.emptyList();
546 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
548 if ( metadataFacet == null )
550 return Collections.emptyList();
552 Map<String, String> map = metadataFacet.toProperties();
553 List<Entry> entries = new ArrayList<Entry>( map.size() );
555 for ( Map.Entry<String, String> entry : map.entrySet() )
557 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
563 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
564 String repositoryId )
565 throws ArchivaRestServiceException
567 ProjectVersionMetadata projectVersionMetadata =
568 getProjectMetadata( groupId, artifactId, version, repositoryId );
570 if ( projectVersionMetadata == null )
572 return Boolean.FALSE;
575 Map<String, String> properties = new HashMap<String, String>();
577 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
579 if ( metadataFacet != null && metadataFacet.toProperties() != null )
581 properties.putAll( metadataFacet.toProperties() );
585 metadataFacet = new GenericMetadataFacet();
588 properties.put( key, value );
590 metadataFacet.fromProperties( properties );
592 projectVersionMetadata.addFacet( metadataFacet );
594 RepositorySession repositorySession = repositorySessionFactory.createSession();
598 MetadataRepository metadataRepository = repositorySession.getRepository();
600 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
602 repositorySession.save();
604 catch ( MetadataRepositoryException e )
606 log.error( e.getMessage(), e );
607 throw new ArchivaRestServiceException( e.getMessage(),
608 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
612 repositorySession.close();
617 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
618 throws ArchivaRestServiceException
620 ProjectVersionMetadata projectVersionMetadata =
621 getProjectMetadata( groupId, artifactId, version, repositoryId );
623 if ( projectVersionMetadata == null )
625 return Boolean.FALSE;
628 GenericMetadataFacet metadataFacet =
629 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
631 if ( metadataFacet != null && metadataFacet.toProperties() != null )
633 Map<String, String> properties = metadataFacet.toProperties();
634 properties.remove( key );
635 metadataFacet.setAdditionalProperties( properties );
642 RepositorySession repositorySession = repositorySessionFactory.createSession();
646 MetadataRepository metadataRepository = repositorySession.getRepository();
648 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
650 repositorySession.save();
652 catch ( MetadataRepositoryException e )
654 log.error( e.getMessage(), e );
655 throw new ArchivaRestServiceException( e.getMessage(),
656 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
660 repositorySession.close();
665 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
666 String classifier, String type, String path,
667 String repositoryId )
668 throws ArchivaRestServiceException
670 List<String> selectedRepos = getSelectedRepos( repositoryId );
673 for ( String repoId : selectedRepos )
676 ManagedRepositoryContent managedRepositoryContent =
677 repositoryContentFactory.getManagedRepositoryContent( repoId );
678 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
679 StringUtils.isEmpty( type ) ? "jar" : type,
681 File file = managedRepositoryContent.toFile( archivaArtifact );
684 return readFileEntries( file, path, repoId );
688 catch ( IOException e )
690 log.error( e.getMessage(), e );
691 throw new ArchivaRestServiceException( e.getMessage(),
692 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
694 catch ( RepositoryNotFoundException e )
696 log.error( e.getMessage(), e );
697 throw new ArchivaRestServiceException( e.getMessage(),
698 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
700 catch ( RepositoryException e )
702 log.error( e.getMessage(), e );
703 throw new ArchivaRestServiceException( e.getMessage(),
704 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
706 return Collections.emptyList();
709 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
710 String repositoryId )
711 throws ArchivaRestServiceException
713 List<String> selectedRepos = getSelectedRepos( repositoryId );
715 List<Artifact> artifactDownloadInfos = new ArrayList<Artifact>();
717 RepositorySession session = repositorySessionFactory.createSession();
719 MetadataResolver metadataResolver = session.getResolver();
723 for ( String repoId : selectedRepos )
725 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
726 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
727 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
728 if ( artifacts != null && !artifacts.isEmpty() )
730 return buildArtifacts( artifacts, repoId );
734 catch ( MetadataResolutionException e )
736 log.error( e.getMessage(), e );
737 throw new ArchivaRestServiceException( e.getMessage(),
738 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
742 if ( session != null )
744 session.closeQuietly();
748 return artifactDownloadInfos;
751 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
752 String type, String path, String repositoryId )
753 throws ArchivaRestServiceException
755 List<String> selectedRepos = getSelectedRepos( repositoryId );
758 for ( String repoId : selectedRepos )
761 ManagedRepositoryContent managedRepositoryContent =
762 repositoryContentFactory.getManagedRepositoryContent( repoId );
763 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
764 StringUtils.isEmpty( type ) ? "jar" : type,
766 File file = managedRepositoryContent.toFile( archivaArtifact );
767 if ( !file.exists() )
769 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
772 if ( StringUtils.isNotBlank( path ) )
774 // zip entry of the path -> path must a real file entry of the archive
775 JarFile jarFile = new JarFile( file );
776 ZipEntry zipEntry = jarFile.getEntry( path );
777 InputStream inputStream = jarFile.getInputStream( zipEntry );
780 return new ArtifactContent( IOUtils.toString( inputStream ), repoId );
784 closeQuietly( jarFile );
785 IOUtils.closeQuietly( inputStream );
788 return new ArtifactContent( FileUtils.readFileToString( file ), repoId );
791 catch ( IOException e )
793 log.error( e.getMessage(), e );
794 throw new ArchivaRestServiceException( e.getMessage(),
795 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
797 catch ( RepositoryNotFoundException e )
799 log.error( e.getMessage(), e );
800 throw new ArchivaRestServiceException( e.getMessage(),
801 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
803 catch ( RepositoryException e )
805 log.error( e.getMessage(), e );
806 throw new ArchivaRestServiceException( e.getMessage(),
807 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
809 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
811 return new ArtifactContent();
814 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
815 String repositoryId )
816 throws ArchivaRestServiceException
818 List<String> selectedRepos = getSelectedRepos( repositoryId );
820 boolean snapshot = VersionUtil.isSnapshot( version );
824 for ( String repoId : selectedRepos )
827 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
829 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
830 && managedRepository.isSnapshots() ) )
834 ManagedRepositoryContent managedRepositoryContent =
835 repositoryContentFactory.getManagedRepositoryContent( repoId );
836 // FIXME default to jar which can be wrong for war zip etc....
837 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
838 StringUtils.isEmpty( classifier )
840 : classifier, "jar", repoId
842 File file = managedRepositoryContent.toFile( archivaArtifact );
844 if ( file != null && file.exists() )
849 // in case of SNAPSHOT we can have timestamped version locally !
850 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
852 File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA );
853 if ( metadataFile.exists() )
857 ArchivaRepositoryMetadata archivaRepositoryMetadata =
858 MavenMetadataReader.read( metadataFile );
859 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
860 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
861 // rebuild file name with timestamped version and build number
862 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
863 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
864 .append( '-' ).append( timeStamp ) //
865 .append( '-' ).append( Integer.toString( buildNumber ) ) //
866 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
867 .append( ".jar" ).toString();
869 File timeStampFile = new File( file.getParent(), timeStampFileName );
870 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
871 if ( timeStampFile.exists() )
876 catch ( XMLException e )
878 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
883 String path = managedRepositoryContent.toPath( archivaArtifact );
885 file = connectors.fetchFromProxies( managedRepositoryContent, path );
887 if ( file != null && file.exists() )
890 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
891 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
896 catch ( RepositoryAdminException e )
898 log.error( e.getMessage(), e );
899 throw new ArchivaRestServiceException( e.getMessage(),
900 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
902 catch ( RepositoryException e )
904 log.error( e.getMessage(), e );
905 throw new ArchivaRestServiceException( e.getMessage(),
906 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
912 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
913 throws ArchivaRestServiceException
915 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
918 public List<Artifact> getArtifacts( String repositoryId )
919 throws ArchivaRestServiceException
921 RepositorySession repositorySession = repositorySessionFactory.createSession();
924 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
925 return buildArtifacts( artifactMetadatas, repositoryId );
927 catch ( MetadataRepositoryException e )
929 throw new ArchivaRestServiceException( e.getMessage(), e );
933 repositorySession.close();
937 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
938 throws ArchivaRestServiceException
940 boolean result = true;
941 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
943 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
944 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
954 //---------------------------
956 //---------------------------
958 private void closeQuietly( JarFile jarFile )
960 if ( jarFile != null )
966 catch ( IOException e )
968 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
973 protected List<ArtifactContentEntry> readFileEntries( File file, String filterPath, String repoId )
976 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<String, ArtifactContentEntry>();
977 int filterDepth = StringUtils.countMatches( filterPath, "/" );
978 /*if ( filterDepth == 0 )
982 JarFile jarFile = new JarFile( file );
985 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
986 while ( jarEntryEnumeration.hasMoreElements() )
988 JarEntry currentEntry = jarEntryEnumeration.nextElement();
989 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
990 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
991 String entryRootPath = getRootPath( cleanedEntryName );
992 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
993 if ( StringUtils.isEmpty( filterPath ) //
994 && !artifactContentEntryMap.containsKey( entryRootPath ) //
995 && depth == filterDepth )
998 artifactContentEntryMap.put( entryRootPath,
999 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1005 if ( StringUtils.startsWith( cleanedEntryName, filterPath ) //
1006 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1008 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1009 !currentEntry.isDirectory(),
1015 if ( StringUtils.isNotEmpty( filterPath ) )
1017 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap =
1018 new HashMap<String, ArtifactContentEntry>();
1020 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1022 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1025 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1026 if ( sorted == null )
1028 return Collections.emptyList();
1030 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1036 if ( jarFile != null )
1041 List<ArtifactContentEntry> sorted = new ArrayList<ArtifactContentEntry>( artifactContentEntryMap.values() );
1042 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1046 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1048 int smallestDepth = Integer.MAX_VALUE;
1049 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<Integer, List<ArtifactContentEntry>>();
1050 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1053 ArtifactContentEntry current = entry.getValue();
1055 if ( current.getDepth() < smallestDepth )
1057 smallestDepth = current.getDepth();
1060 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1062 if ( currentList == null )
1064 currentList = new ArrayList<ArtifactContentEntry>();
1065 currentList.add( current );
1066 perDepthList.put( current.getDepth(), currentList );
1070 currentList.add( current );
1075 return perDepthList.get( smallestDepth );
1080 * @return org/apache -> org , org -> org
1082 private String getRootPath( String path )
1084 if ( StringUtils.contains( path, '/' ) )
1086 return StringUtils.substringBefore( path, "/" );
1091 private List<String> getSelectedRepos( String repositoryId )
1092 throws ArchivaRestServiceException
1095 List<String> selectedRepos = getObservableRepos();
1097 if ( CollectionUtils.isEmpty( selectedRepos ) )
1099 return Collections.emptyList();
1102 if ( StringUtils.isNotEmpty( repositoryId ) )
1104 // check user has karma on the repository
1105 if ( !selectedRepos.contains( repositoryId ) )
1107 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1108 Response.Status.FORBIDDEN.getStatusCode(), null );
1110 selectedRepos = Collections.singletonList( repositoryId );
1112 return selectedRepos;
1116 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1117 Collection<String> repoIds, String n )
1118 throws MetadataResolutionException
1120 Set<String> subNamespaces = new LinkedHashSet<String>();
1121 for ( String repoId : repoIds )
1123 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1125 if ( subNamespaces.size() != 1 )
1127 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1132 for ( String repoId : repoIds )
1134 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1135 if ( projects != null && !projects.isEmpty() )
1137 log.debug( "{} is not collapsible as it has projects", n );
1141 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1142 n + "." + subNamespaces.iterator().next() );
1146 public Cache getVersionMetadataCache()
1148 return versionMetadataCache;
1151 public void setVersionMetadataCache( Cache versionMetadataCache )
1153 this.versionMetadataCache = versionMetadataCache;