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.repository.ManagedRepositoryContent;
45 import org.apache.archiva.repository.RepositoryContentFactory;
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.FileUtils;
63 import org.apache.commons.io.IOUtils;
64 import org.apache.commons.lang.StringUtils;
65 import org.springframework.stereotype.Service;
67 import javax.inject.Inject;
68 import javax.inject.Named;
69 import javax.ws.rs.core.Response;
71 import java.io.IOException;
72 import java.io.InputStream;
73 import java.util.ArrayList;
74 import java.util.Collection;
75 import java.util.Collections;
76 import java.util.Enumeration;
77 import java.util.HashMap;
78 import java.util.LinkedHashSet;
79 import java.util.List;
82 import java.util.jar.JarEntry;
83 import java.util.jar.JarFile;
84 import java.util.zip.ZipEntry;
87 * @author Olivier Lamy
90 @Service( "browseService#rest" )
91 public class DefaultBrowseService
92 extends AbstractRestService
93 implements BrowseService
97 private DependencyTreeBuilder dependencyTreeBuilder;
100 private RepositoryContentFactory repositoryContentFactory;
103 @Named( value = "repositoryProxyConnectors#default" )
104 private RepositoryProxyConnectors connectors;
106 public BrowseResult getRootGroups( String repositoryId )
107 throws ArchivaRestServiceException
109 List<String> selectedRepos = getSelectedRepos( repositoryId );
111 Set<String> namespaces = new LinkedHashSet<String>();
113 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
114 // it is located here to avoid the content repository implementation needing to do too much for what
115 // is essentially presentation code
116 Set<String> namespacesToCollapse;
117 RepositorySession repositorySession = repositorySessionFactory.createSession();
120 MetadataResolver metadataResolver = repositorySession.getResolver();
121 namespacesToCollapse = new LinkedHashSet<String>();
123 for ( String repoId : selectedRepos )
125 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
127 for ( String n : namespacesToCollapse )
129 // TODO: check performance of this
130 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
133 catch ( MetadataResolutionException e )
135 throw new ArchivaRestServiceException( e.getMessage(),
136 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
140 repositorySession.close();
143 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<BrowseResultEntry>( namespaces.size() );
144 for ( String namespace : namespaces )
146 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
149 Collections.sort( browseGroupResultEntries );
150 return new BrowseResult( browseGroupResultEntries );
153 public BrowseResult browseGroupId( String groupId, String repositoryId )
154 throws ArchivaRestServiceException
156 List<String> selectedRepos = getSelectedRepos( repositoryId );
158 Set<String> projects = new LinkedHashSet<String>();
160 RepositorySession repositorySession = repositorySessionFactory.createSession();
161 Set<String> namespaces;
164 MetadataResolver metadataResolver = repositorySession.getResolver();
166 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
167 for ( String repoId : selectedRepos )
169 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
171 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
174 // TODO: this logic should be optional, particularly remembering we want to keep this code simple
175 // it is located here to avoid the content repository implementation needing to do too much for what
176 // is essentially presentation code
177 namespaces = new LinkedHashSet<String>();
178 for ( String n : namespacesToCollapse )
180 // TODO: check performance of this
182 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
185 catch ( MetadataResolutionException e )
187 throw new ArchivaRestServiceException( e.getMessage(),
188 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
192 repositorySession.close();
194 List<BrowseResultEntry> browseGroupResultEntries =
195 new ArrayList<BrowseResultEntry>( namespaces.size() + projects.size() );
196 for ( String namespace : namespaces )
198 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
200 for ( String project : projects )
202 browseGroupResultEntries.add(
203 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
205 Collections.sort( browseGroupResultEntries );
206 return new BrowseResult( browseGroupResultEntries );
210 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
211 throws ArchivaRestServiceException
213 List<String> selectedRepos = getSelectedRepos( repositoryId );
217 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
218 return new VersionsList( new ArrayList<String>( versions ) );
220 catch ( MetadataResolutionException e )
222 throw new ArchivaRestServiceException( e.getMessage(),
223 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
228 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
229 throws MetadataResolutionException
232 RepositorySession repositorySession = repositorySessionFactory.createSession();
235 MetadataResolver metadataResolver = repositorySession.getResolver();
237 Set<String> versions = new LinkedHashSet<String>();
239 for ( String repoId : selectedRepos )
241 Collection<String> projectVersions =
242 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
243 versions.addAll( projectVersions );
246 List<String> sortedVersions = new ArrayList<String>( versions );
248 Collections.sort( sortedVersions, VersionComparator.getInstance() );
250 return sortedVersions;
254 repositorySession.close();
258 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
259 String repositoryId )
260 throws ArchivaRestServiceException
262 List<String> selectedRepos = getSelectedRepos( repositoryId );
264 RepositorySession repositorySession = null;
267 repositorySession = repositorySessionFactory.createSession();
269 MetadataResolver metadataResolver = repositorySession.getResolver();
271 ProjectVersionMetadata versionMetadata = null;
272 for ( String repoId : selectedRepos )
274 if ( versionMetadata == null || versionMetadata.isIncomplete() )
279 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
282 catch ( MetadataResolutionException e )
284 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
285 groupId, artifactId, repoId, e.getMessage() );
290 return versionMetadata;
294 if ( repositorySession != null )
296 repositorySession.close();
302 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
303 throws ArchivaRestServiceException
306 List<String> selectedRepos = getSelectedRepos( repositoryId );
308 RepositorySession repositorySession = null;
312 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
314 repositorySession = repositorySessionFactory.createSession();
316 MetadataResolver metadataResolver = repositorySession.getResolver();
318 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
320 MavenProjectFacet mavenFacet = new MavenProjectFacet();
321 mavenFacet.setGroupId( groupId );
322 mavenFacet.setArtifactId( artifactId );
323 sharedModel.addFacet( mavenFacet );
325 boolean isFirstVersion = true;
327 for ( String version : projectVersions )
329 ProjectVersionMetadata versionMetadata = null;
330 for ( String repoId : selectedRepos )
332 if ( versionMetadata == null || versionMetadata.isIncomplete() )
337 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
340 catch ( MetadataResolutionException e )
342 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
343 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
348 if ( versionMetadata == null )
353 if ( isFirstVersion )
355 sharedModel = versionMetadata;
356 sharedModel.setId( null );
360 MavenProjectFacet versionMetadataMavenFacet =
361 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
362 if ( versionMetadataMavenFacet != null )
364 if ( mavenFacet.getPackaging() != null //
365 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
366 versionMetadataMavenFacet.getPackaging() ) )
368 mavenFacet.setPackaging( null );
372 if ( StringUtils.isEmpty( sharedModel.getName() ) //
373 && !StringUtils.isEmpty( versionMetadata.getName() ) )
375 sharedModel.setName( versionMetadata.getName() );
378 if ( sharedModel.getDescription() != null //
379 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
380 versionMetadata.getDescription() ) )
382 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
383 ? versionMetadata.getDescription()
387 if ( sharedModel.getIssueManagement() != null //
388 && versionMetadata.getIssueManagement() != null //
389 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
390 versionMetadata.getIssueManagement().getUrl() ) )
392 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
395 if ( sharedModel.getCiManagement() != null //
396 && versionMetadata.getCiManagement() != null //
397 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
398 versionMetadata.getCiManagement().getUrl() ) )
400 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
403 if ( sharedModel.getOrganization() != null //
404 && versionMetadata.getOrganization() != null //
405 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
406 versionMetadata.getOrganization().getName() ) )
408 sharedModel.setOrganization( versionMetadata.getOrganization() );
411 if ( sharedModel.getUrl() != null //
412 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
414 sharedModel.setUrl( versionMetadata.getUrl() );
418 isFirstVersion = false;
422 catch ( MetadataResolutionException e )
424 throw new ArchivaRestServiceException( e.getMessage(),
425 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
429 if ( repositorySession != null )
431 repositorySession.close();
436 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
437 throws ArchivaRestServiceException
439 List<String> selectedRepos = getSelectedRepos( repositoryId );
444 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
447 catch ( Exception e )
449 log.error( e.getMessage(), e );
452 return Collections.emptyList();
455 public List<ManagedRepository> getUserRepositories()
456 throws ArchivaRestServiceException
460 return userRepositories.getAccessibleRepositories( getPrincipal() );
462 catch ( ArchivaSecurityException e )
464 throw new ArchivaRestServiceException( "repositories.read.observable.error",
465 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
469 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
470 throws ArchivaRestServiceException
472 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
473 // TODO: what if we get duplicates across repositories?
474 RepositorySession repositorySession = repositorySessionFactory.createSession();
477 MetadataResolver metadataResolver = repositorySession.getResolver();
478 for ( String repoId : getObservableRepos() )
480 // TODO: what about if we want to see this irrespective of version?
482 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId, version )
486 catch ( MetadataResolutionException e )
488 throw new ArchivaRestServiceException( e.getMessage(),
489 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
493 repositorySession.close();
496 List<Artifact> artifacts = new ArrayList<Artifact>( references.size() );
498 for ( ProjectVersionReference projectVersionReference : references )
500 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
501 projectVersionReference.getProjectVersion() ) );
506 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
507 throws ArchivaRestServiceException
509 ProjectVersionMetadata projectVersionMetadata =
510 getProjectMetadata( groupId, artifactId, version, repositoryId );
511 if ( projectVersionMetadata == null )
513 return Collections.emptyList();
515 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
517 if ( metadataFacet == null )
519 return Collections.emptyList();
521 Map<String, String> map = metadataFacet.toProperties();
522 List<Entry> entries = new ArrayList<Entry>( map.size() );
524 for ( Map.Entry<String, String> entry : map.entrySet() )
526 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
532 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
533 String repositoryId )
534 throws ArchivaRestServiceException
536 ProjectVersionMetadata projectVersionMetadata =
537 getProjectMetadata( groupId, artifactId, version, repositoryId );
539 if ( projectVersionMetadata == null )
541 return Boolean.FALSE;
544 Map<String, String> properties = new HashMap<String, String>();
546 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
548 if ( metadataFacet != null && metadataFacet.toProperties() != null )
550 properties.putAll( metadataFacet.toProperties() );
554 metadataFacet = new GenericMetadataFacet();
557 properties.put( key, value );
559 metadataFacet.fromProperties( properties );
561 projectVersionMetadata.addFacet( metadataFacet );
563 RepositorySession repositorySession = repositorySessionFactory.createSession();
567 MetadataRepository metadataRepository = repositorySession.getRepository();
569 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
571 repositorySession.save();
573 catch ( MetadataRepositoryException e )
575 log.error( e.getMessage(), e );
576 throw new ArchivaRestServiceException( e.getMessage(),
577 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
581 repositorySession.close();
586 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
587 throws ArchivaRestServiceException
589 ProjectVersionMetadata projectVersionMetadata =
590 getProjectMetadata( groupId, artifactId, version, repositoryId );
592 if ( projectVersionMetadata == null )
594 return Boolean.FALSE;
597 GenericMetadataFacet metadataFacet =
598 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
600 if ( metadataFacet != null && metadataFacet.toProperties() != null )
602 Map<String, String> properties = metadataFacet.toProperties();
603 properties.remove( key );
604 metadataFacet.setAdditionalProperties( properties );
611 RepositorySession repositorySession = repositorySessionFactory.createSession();
615 MetadataRepository metadataRepository = repositorySession.getRepository();
617 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
619 repositorySession.save();
621 catch ( MetadataRepositoryException e )
623 log.error( e.getMessage(), e );
624 throw new ArchivaRestServiceException( e.getMessage(),
625 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
629 repositorySession.close();
634 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
635 String classifier, String type, String path,
636 String repositoryId )
637 throws ArchivaRestServiceException
639 List<String> selectedRepos = getSelectedRepos( repositoryId );
642 for ( String repoId : selectedRepos )
645 ManagedRepositoryContent managedRepositoryContent =
646 repositoryContentFactory.getManagedRepositoryContent( repoId );
647 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
648 StringUtils.isEmpty( type ) ? "jar" : type,
650 File file = managedRepositoryContent.toFile( archivaArtifact );
653 return readFileEntries( file, path, repoId );
657 catch ( IOException e )
659 log.error( e.getMessage(), e );
660 throw new ArchivaRestServiceException( e.getMessage(),
661 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
663 catch ( RepositoryNotFoundException e )
665 log.error( e.getMessage(), e );
666 throw new ArchivaRestServiceException( e.getMessage(),
667 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
669 catch ( RepositoryException e )
671 log.error( e.getMessage(), e );
672 throw new ArchivaRestServiceException( e.getMessage(),
673 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
675 return Collections.emptyList();
678 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
679 String repositoryId )
680 throws ArchivaRestServiceException
682 List<String> selectedRepos = getSelectedRepos( repositoryId );
684 List<Artifact> artifactDownloadInfos = new ArrayList<Artifact>();
686 RepositorySession session = repositorySessionFactory.createSession();
688 MetadataResolver metadataResolver = session.getResolver();
692 for ( String repoId : selectedRepos )
694 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
695 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
696 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
697 if ( artifacts != null && !artifacts.isEmpty() )
699 return buildArtifacts( artifacts, repoId );
703 catch ( MetadataResolutionException e )
705 log.error( e.getMessage(), e );
706 throw new ArchivaRestServiceException( e.getMessage(),
707 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
711 if ( session != null )
713 session.closeQuietly();
717 return artifactDownloadInfos;
720 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
721 String type, String path, String repositoryId )
722 throws ArchivaRestServiceException
724 List<String> selectedRepos = getSelectedRepos( repositoryId );
727 for ( String repoId : selectedRepos )
730 ManagedRepositoryContent managedRepositoryContent =
731 repositoryContentFactory.getManagedRepositoryContent( repoId );
732 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
733 StringUtils.isEmpty( type ) ? "jar" : type,
735 File file = managedRepositoryContent.toFile( archivaArtifact );
736 if ( !file.exists() )
738 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
741 if ( StringUtils.isNotBlank( path ) )
743 // zip entry of the path -> path must a real file entry of the archive
744 JarFile jarFile = new JarFile( file );
745 ZipEntry zipEntry = jarFile.getEntry( path );
746 InputStream inputStream = jarFile.getInputStream( zipEntry );
749 return new ArtifactContent( IOUtils.toString( inputStream ), repoId );
753 closeQuietly( jarFile );
754 IOUtils.closeQuietly( inputStream );
757 return new ArtifactContent( FileUtils.readFileToString( file ), repoId );
760 catch ( IOException e )
762 log.error( e.getMessage(), e );
763 throw new ArchivaRestServiceException( e.getMessage(),
764 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
766 catch ( RepositoryNotFoundException e )
768 log.error( e.getMessage(), e );
769 throw new ArchivaRestServiceException( e.getMessage(),
770 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
772 catch ( RepositoryException e )
774 log.error( e.getMessage(), e );
775 throw new ArchivaRestServiceException( e.getMessage(),
776 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
778 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
780 return new ArtifactContent();
783 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
784 String repositoryId )
785 throws ArchivaRestServiceException
787 List<String> selectedRepos = getSelectedRepos( repositoryId );
789 boolean snapshot = VersionUtil.isSnapshot( version );
793 for ( String repoId : selectedRepos )
796 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
798 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
799 && managedRepository.isSnapshots() ) )
803 ManagedRepositoryContent managedRepositoryContent =
804 repositoryContentFactory.getManagedRepositoryContent( repoId );
805 // FIXME default to jar which can be wrong for war zip etc....
806 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
807 StringUtils.isEmpty( classifier )
809 : classifier, "jar", repoId
811 File file = managedRepositoryContent.toFile( archivaArtifact );
813 if ( file != null && file.exists() )
818 // in case of SNAPSHOT we can have timestamped version locally !
819 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
821 File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA );
822 if ( metadataFile.exists() )
826 ArchivaRepositoryMetadata archivaRepositoryMetadata =
827 MavenMetadataReader.read( metadataFile );
828 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
829 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
830 // rebuild file name with timestamped version and build number
831 String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
832 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
833 .append( '-' ).append( timeStamp ) //
834 .append( '-' ).append( Integer.toString( buildNumber ) ) //
835 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
836 .append( ".jar" ).toString();
838 File timeStampFile = new File( file.getParent(), timeStampFileName );
839 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
840 if ( timeStampFile.exists() )
845 catch ( XMLException e )
847 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
852 String path = managedRepositoryContent.toPath( archivaArtifact );
854 file = connectors.fetchFromProxies( managedRepositoryContent, path );
856 if ( file != null && file.exists() )
859 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
860 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
865 catch ( RepositoryAdminException e )
867 log.error( e.getMessage(), e );
868 throw new ArchivaRestServiceException( e.getMessage(),
869 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
871 catch ( RepositoryException e )
873 log.error( e.getMessage(), e );
874 throw new ArchivaRestServiceException( e.getMessage(),
875 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
881 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
882 throws ArchivaRestServiceException
884 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
887 public List<Artifact> getArtifacts( String repositoryId )
888 throws ArchivaRestServiceException
890 RepositorySession repositorySession = repositorySessionFactory.createSession();
893 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
894 return buildArtifacts( artifactMetadatas, repositoryId );
896 catch ( MetadataRepositoryException e )
898 throw new ArchivaRestServiceException( e.getMessage(), e );
902 repositorySession.close();
906 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
907 throws ArchivaRestServiceException
909 boolean result = true;
910 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
912 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
913 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
923 //---------------------------
925 //---------------------------
927 private void closeQuietly( JarFile jarFile )
929 if ( jarFile != null )
935 catch ( IOException e )
937 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
942 protected List<ArtifactContentEntry> readFileEntries( File file, String filterPath, String repoId )
945 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<String, ArtifactContentEntry>();
946 int filterDepth = StringUtils.countMatches( filterPath, "/" );
947 /*if ( filterDepth == 0 )
951 JarFile jarFile = new JarFile( file );
954 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
955 while ( jarEntryEnumeration.hasMoreElements() )
957 JarEntry currentEntry = jarEntryEnumeration.nextElement();
958 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
959 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
960 String entryRootPath = getRootPath( cleanedEntryName );
961 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
962 if ( StringUtils.isEmpty( filterPath ) //
963 && !artifactContentEntryMap.containsKey( entryRootPath ) //
964 && depth == filterDepth )
967 artifactContentEntryMap.put( entryRootPath,
968 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
974 if ( StringUtils.startsWith( cleanedEntryName, filterPath ) //
975 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
977 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
978 !currentEntry.isDirectory(),
984 if ( StringUtils.isNotEmpty( filterPath ) )
986 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap =
987 new HashMap<String, ArtifactContentEntry>();
989 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
991 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
994 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
995 if ( sorted == null )
997 return Collections.emptyList();
999 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1005 if ( jarFile != null )
1010 List<ArtifactContentEntry> sorted = new ArrayList<ArtifactContentEntry>( artifactContentEntryMap.values() );
1011 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1015 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1017 int smallestDepth = Integer.MAX_VALUE;
1018 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<Integer, List<ArtifactContentEntry>>();
1019 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1022 ArtifactContentEntry current = entry.getValue();
1024 if ( current.getDepth() < smallestDepth )
1026 smallestDepth = current.getDepth();
1029 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1031 if ( currentList == null )
1033 currentList = new ArrayList<ArtifactContentEntry>();
1034 currentList.add( current );
1035 perDepthList.put( current.getDepth(), currentList );
1039 currentList.add( current );
1044 return perDepthList.get( smallestDepth );
1049 * @return org/apache -> org , org -> org
1051 private String getRootPath( String path )
1053 if ( StringUtils.contains( path, '/' ) )
1055 return StringUtils.substringBefore( path, "/" );
1060 private List<String> getSelectedRepos( String repositoryId )
1061 throws ArchivaRestServiceException
1064 List<String> selectedRepos = getObservableRepos();
1066 if ( CollectionUtils.isEmpty( selectedRepos ) )
1068 return Collections.emptyList();
1071 if ( StringUtils.isNotEmpty( repositoryId ) )
1073 // check user has karma on the repository
1074 if ( !selectedRepos.contains( repositoryId ) )
1076 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1077 Response.Status.FORBIDDEN.getStatusCode(), null );
1079 selectedRepos = Collections.singletonList( repositoryId );
1081 return selectedRepos;
1085 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1086 Collection<String> repoIds, String n )
1087 throws MetadataResolutionException
1089 Set<String> subNamespaces = new LinkedHashSet<String>();
1090 for ( String repoId : repoIds )
1092 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1094 if ( subNamespaces.size() != 1 )
1096 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1101 for ( String repoId : repoIds )
1103 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1104 if ( projects != null && !projects.isEmpty() )
1106 log.debug( "{} is not collapsible as it has projects", n );
1110 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1111 n + "." + subNamespaces.iterator().next() );