]> source.dussan.org Git - archiva.git/blob
5bce8e21139d29c702d9d45d21488996d16e64dd
[archiva.git] /
1 package org.apache.archiva.rest.services;
2 /*
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
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
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
18  * under the License.
19  */
20
21 import org.apache.archiva.admin.model.beans.ManagedRepository;
22 import org.apache.archiva.common.utils.VersionComparator;
23 import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder;
24 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
25 import org.apache.archiva.metadata.model.ArtifactMetadata;
26 import org.apache.archiva.metadata.model.MetadataFacet;
27 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
28 import org.apache.archiva.metadata.model.ProjectVersionReference;
29 import org.apache.archiva.metadata.repository.MetadataRepository;
30 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
31 import org.apache.archiva.metadata.repository.MetadataResolutionException;
32 import org.apache.archiva.metadata.repository.MetadataResolver;
33 import org.apache.archiva.metadata.repository.RepositorySession;
34 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
35 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
36 import org.apache.archiva.model.ArchivaArtifact;
37 import org.apache.archiva.repository.ManagedRepositoryContent;
38 import org.apache.archiva.repository.RepositoryContentFactory;
39 import org.apache.archiva.repository.RepositoryException;
40 import org.apache.archiva.repository.RepositoryNotFoundException;
41 import org.apache.archiva.rest.api.model.Artifact;
42 import org.apache.archiva.rest.api.model.ArtifactContentEntry;
43 import org.apache.archiva.rest.api.model.ArtifactDownloadInfo;
44 import org.apache.archiva.rest.api.model.BrowseResult;
45 import org.apache.archiva.rest.api.model.BrowseResultEntry;
46 import org.apache.archiva.rest.api.model.Entry;
47 import org.apache.archiva.rest.api.model.TreeEntry;
48 import org.apache.archiva.rest.api.model.VersionsList;
49 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
50 import org.apache.archiva.rest.api.services.BrowseService;
51 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
52 import org.apache.archiva.rest.services.utils.ArtifactDownloadInfoBuilder;
53 import org.apache.archiva.rest.services.utils.TreeDependencyNodeVisitor;
54 import org.apache.archiva.security.ArchivaSecurityException;
55 import org.apache.commons.collections.CollectionUtils;
56 import org.apache.commons.io.FileUtils;
57 import org.apache.commons.io.IOUtils;
58 import org.apache.commons.lang.StringUtils;
59 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
60 import org.springframework.stereotype.Service;
61
62 import javax.inject.Inject;
63 import javax.ws.rs.core.Response;
64 import java.io.File;
65 import java.io.IOException;
66 import java.io.InputStream;
67 import java.util.ArrayList;
68 import java.util.Collection;
69 import java.util.Collections;
70 import java.util.Enumeration;
71 import java.util.HashMap;
72 import java.util.LinkedHashSet;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Set;
76 import java.util.jar.JarEntry;
77 import java.util.jar.JarFile;
78 import java.util.zip.ZipEntry;
79
80 /**
81  * @author Olivier Lamy
82  * @since 1.4-M3
83  */
84 @Service( "browseService#rest" )
85 public class DefaultBrowseService
86     extends AbstractRestService
87     implements BrowseService
88 {
89
90     @Inject
91     private DependencyTreeBuilder dependencyTreeBuilder;
92
93     @Inject
94     private RepositoryContentFactory repositoryContentFactory;
95
96     public BrowseResult getRootGroups( String repositoryId )
97         throws ArchivaRestServiceException
98     {
99         List<String> selectedRepos = getSelectedRepos( repositoryId );
100
101         Set<String> namespaces = new LinkedHashSet<String>();
102
103         // TODO: this logic should be optional, particularly remembering we want to keep this code simple
104         //       it is located here to avoid the content repository implementation needing to do too much for what
105         //       is essentially presentation code
106         Set<String> namespacesToCollapse;
107         RepositorySession repositorySession = repositorySessionFactory.createSession();
108         try
109         {
110             MetadataResolver metadataResolver = repositorySession.getResolver();
111             namespacesToCollapse = new LinkedHashSet<String>();
112
113             for ( String repoId : selectedRepos )
114             {
115                 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
116             }
117             for ( String n : namespacesToCollapse )
118             {
119                 // TODO: check performance of this
120                 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
121             }
122         }
123         catch ( MetadataResolutionException e )
124         {
125             throw new ArchivaRestServiceException( e.getMessage(),
126                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
127         }
128         finally
129         {
130             repositorySession.close();
131         }
132
133         List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<BrowseResultEntry>( namespaces.size() );
134         for ( String namespace : namespaces )
135         {
136             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
137         }
138
139         Collections.sort( browseGroupResultEntries );
140         return new BrowseResult( browseGroupResultEntries );
141     }
142
143     public BrowseResult browseGroupId( String groupId, String repositoryId )
144         throws ArchivaRestServiceException
145     {
146         List<String> selectedRepos = getSelectedRepos( repositoryId );
147
148         Set<String> projects = new LinkedHashSet<String>();
149
150         RepositorySession repositorySession = repositorySessionFactory.createSession();
151         Set<String> namespaces;
152         try
153         {
154             MetadataResolver metadataResolver = repositorySession.getResolver();
155
156             Set<String> namespacesToCollapse = new LinkedHashSet<String>();
157             for ( String repoId : selectedRepos )
158             {
159                 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
160
161                 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
162             }
163
164             // TODO: this logic should be optional, particularly remembering we want to keep this code simple
165             // it is located here to avoid the content repository implementation needing to do too much for what
166             // is essentially presentation code
167             namespaces = new LinkedHashSet<String>();
168             for ( String n : namespacesToCollapse )
169             {
170                 // TODO: check performance of this
171                 namespaces.add(
172                     collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
173             }
174         }
175         catch ( MetadataResolutionException e )
176         {
177             throw new ArchivaRestServiceException( e.getMessage(),
178                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
179         }
180         finally
181         {
182             repositorySession.close();
183         }
184         List<BrowseResultEntry> browseGroupResultEntries =
185             new ArrayList<BrowseResultEntry>( namespaces.size() + projects.size() );
186         for ( String namespace : namespaces )
187         {
188             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
189         }
190         for ( String project : projects )
191         {
192             browseGroupResultEntries.add( new BrowseResultEntry( groupId + '.' + project, true ) );
193         }
194         Collections.sort( browseGroupResultEntries );
195         return new BrowseResult( browseGroupResultEntries );
196
197     }
198
199     public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
200         throws ArchivaRestServiceException
201     {
202         List<String> selectedRepos = getSelectedRepos( repositoryId );
203
204         try
205         {
206             return new VersionsList( new ArrayList<String>( getVersions( selectedRepos, groupId, artifactId ) ) );
207         }
208         catch ( MetadataResolutionException e )
209         {
210             throw new ArchivaRestServiceException( e.getMessage(),
211                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
212         }
213
214     }
215
216     private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
217         throws MetadataResolutionException
218
219     {
220         RepositorySession repositorySession = repositorySessionFactory.createSession();
221         try
222         {
223             MetadataResolver metadataResolver = repositorySession.getResolver();
224
225             Set<String> versions = new LinkedHashSet<String>();
226
227             for ( String repoId : selectedRepos )
228             {
229                 versions.addAll(
230                     metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId ) );
231             }
232
233             List<String> sortedVersions = new ArrayList<String>( versions );
234
235             Collections.sort( sortedVersions, VersionComparator.getInstance() );
236
237             return sortedVersions;
238         }
239         finally
240         {
241             repositorySession.close();
242         }
243     }
244
245     public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
246                                                       String repositoryId )
247         throws ArchivaRestServiceException
248     {
249         List<String> selectedRepos = getSelectedRepos( repositoryId );
250
251         RepositorySession repositorySession = null;
252         try
253         {
254             repositorySession = repositorySessionFactory.createSession();
255
256             MetadataResolver metadataResolver = repositorySession.getResolver();
257
258             ProjectVersionMetadata versionMetadata = null;
259             for ( String repoId : selectedRepos )
260             {
261                 if ( versionMetadata == null || versionMetadata.isIncomplete() )
262                 {
263                     try
264                     {
265                         versionMetadata =
266                             metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
267                                                                     version );
268                     }
269                     catch ( MetadataResolutionException e )
270                     {
271                         log.error(
272                             "Skipping invalid metadata while compiling shared model for " + groupId + ":" + artifactId
273                                 + " in repo " + repoId + ": " + e.getMessage() );
274                     }
275                 }
276             }
277
278             return versionMetadata;
279         }
280         finally
281         {
282             if ( repositorySession != null )
283             {
284                 repositorySession.close();
285             }
286         }
287
288     }
289
290     public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
291         throws ArchivaRestServiceException
292     {
293
294         List<String> selectedRepos = getSelectedRepos( repositoryId );
295
296         RepositorySession repositorySession = null;
297         try
298         {
299
300             Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
301
302             repositorySession = repositorySessionFactory.createSession();
303
304             MetadataResolver metadataResolver = repositorySession.getResolver();
305
306             ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
307
308             MavenProjectFacet mavenFacet = new MavenProjectFacet();
309             mavenFacet.setGroupId( groupId );
310             mavenFacet.setArtifactId( artifactId );
311             sharedModel.addFacet( mavenFacet );
312
313             boolean isFirstVersion = true;
314
315             for ( String version : projectVersions )
316             {
317                 ProjectVersionMetadata versionMetadata = null;
318                 for ( String repoId : selectedRepos )
319                 {
320                     if ( versionMetadata == null || versionMetadata.isIncomplete() )
321                     {
322                         try
323                         {
324                             versionMetadata =
325                                 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
326                                                                         version );
327                         }
328                         catch ( MetadataResolutionException e )
329                         {
330                             log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
331                                            + artifactId + " in repo " + repoId + ": " + e.getMessage() );
332                         }
333                     }
334                 }
335
336                 if ( versionMetadata == null )
337                 {
338                     continue;
339                 }
340
341                 if ( isFirstVersion )
342                 {
343                     sharedModel = versionMetadata;
344                     sharedModel.setId( null );
345                 }
346                 else
347                 {
348                     MavenProjectFacet versionMetadataMavenFacet =
349                         (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
350                     if ( versionMetadataMavenFacet != null )
351                     {
352                         if ( mavenFacet.getPackaging() != null && !StringUtils.equalsIgnoreCase(
353                             mavenFacet.getPackaging(), versionMetadataMavenFacet.getPackaging() ) )
354                         {
355                             mavenFacet.setPackaging( null );
356                         }
357                     }
358
359                     if ( StringUtils.isEmpty( sharedModel.getName() ) && !StringUtils.isEmpty(
360                         versionMetadata.getName() ) )
361                     {
362                         sharedModel.setName( versionMetadata.getName() );
363                     }
364
365                     if ( sharedModel.getDescription() != null && !StringUtils.equalsIgnoreCase(
366                         sharedModel.getDescription(), versionMetadata.getDescription() ) )
367                     {
368                         sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
369                                                         ? versionMetadata.getDescription()
370                                                         : "" );
371                     }
372
373                     if ( sharedModel.getIssueManagement() != null && versionMetadata.getIssueManagement() != null
374                         && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
375                                                           versionMetadata.getIssueManagement().getUrl() ) )
376                     {
377                         sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
378                     }
379
380                     if ( sharedModel.getCiManagement() != null && versionMetadata.getCiManagement() != null
381                         && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
382                                                           versionMetadata.getCiManagement().getUrl() ) )
383                     {
384                         sharedModel.setCiManagement( versionMetadata.getCiManagement() );
385                     }
386
387                     if ( sharedModel.getOrganization() != null && versionMetadata.getOrganization() != null
388                         && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
389                                                           versionMetadata.getOrganization().getName() ) )
390                     {
391                         sharedModel.setOrganization( versionMetadata.getOrganization() );
392                     }
393
394                     if ( sharedModel.getUrl() != null && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(),
395                                                                                         versionMetadata.getUrl() ) )
396                     {
397                         sharedModel.setUrl( versionMetadata.getUrl() );
398                     }
399                 }
400
401                 isFirstVersion = false;
402             }
403             return sharedModel;
404         }
405         catch ( MetadataResolutionException e )
406         {
407             throw new ArchivaRestServiceException( e.getMessage(),
408                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
409         }
410         finally
411         {
412             if ( repositorySession != null )
413             {
414                 repositorySession.close();
415             }
416         }
417     }
418
419     public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
420         throws ArchivaRestServiceException
421     {
422         List<String> selectedRepos = getSelectedRepos( repositoryId );
423
424         List<TreeEntry> treeEntries = new ArrayList<TreeEntry>();
425         TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
426         try
427         {
428             dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version,
429                                                        treeDependencyNodeVisitor );
430         }
431         catch ( DependencyTreeBuilderException e )
432         {
433             throw new ArchivaRestServiceException( e.getMessage(),
434                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
435         }
436         return treeEntries;
437     }
438
439     public List<ManagedRepository> getUserRepositories()
440         throws ArchivaRestServiceException
441     {
442         try
443         {
444             return userRepositories.getAccessibleRepositories( getPrincipal() );
445         }
446         catch ( ArchivaSecurityException e )
447         {
448             throw new ArchivaRestServiceException( "repositories.read.observable.error",
449                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
450         }
451     }
452
453     public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
454         throws ArchivaRestServiceException
455     {
456         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
457         // TODO: what if we get duplicates across repositories?
458         RepositorySession repositorySession = repositorySessionFactory.createSession();
459         try
460         {
461             MetadataResolver metadataResolver = repositorySession.getResolver();
462             for ( String repoId : getObservableRepos() )
463             {
464                 // TODO: what about if we want to see this irrespective of version?
465                 references.addAll(
466                     metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
467                                                                version ) );
468             }
469         }
470         catch ( MetadataResolutionException e )
471         {
472             throw new ArchivaRestServiceException( e.getMessage(),
473                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
474         }
475         finally
476         {
477             repositorySession.close();
478         }
479
480         List<Artifact> artifacts = new ArrayList<Artifact>( references.size() );
481
482         for ( ProjectVersionReference projectVersionReference : references )
483         {
484             artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
485                                          projectVersionReference.getProjectVersion() ) );
486         }
487         return artifacts;
488     }
489
490     public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
491         throws ArchivaRestServiceException
492     {
493         ProjectVersionMetadata projectVersionMetadata =
494             getProjectMetadata( groupId, artifactId, version, repositoryId );
495         if ( projectVersionMetadata == null )
496         {
497             return Collections.emptyList();
498         }
499         MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
500
501         if ( metadataFacet == null )
502         {
503             return Collections.emptyList();
504         }
505         Map<String, String> map = metadataFacet.toProperties();
506         List<Entry> entries = new ArrayList<Entry>( map.size() );
507
508         for ( Map.Entry<String, String> entry : map.entrySet() )
509         {
510             entries.add( new Entry( entry.getKey(), entry.getValue() ) );
511         }
512
513         return entries;
514     }
515
516     public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
517                                 String repositoryId )
518         throws ArchivaRestServiceException
519     {
520         ProjectVersionMetadata projectVersionMetadata =
521             getProjectMetadata( groupId, artifactId, version, repositoryId );
522
523         if ( projectVersionMetadata == null )
524         {
525             return Boolean.FALSE;
526         }
527
528         Map<String, String> properties = new HashMap<String, String>();
529
530         MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
531
532         if ( metadataFacet != null && metadataFacet.toProperties() != null )
533         {
534             properties.putAll( metadataFacet.toProperties() );
535         }
536         else
537         {
538             metadataFacet = new GenericMetadataFacet();
539         }
540
541         properties.put( key, value );
542
543         metadataFacet.fromProperties( properties );
544
545         projectVersionMetadata.addFacet( metadataFacet );
546
547         RepositorySession repositorySession = repositorySessionFactory.createSession();
548
549         try
550         {
551             MetadataRepository metadataRepository = repositorySession.getRepository();
552
553             metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
554
555             repositorySession.save();
556         }
557         catch ( MetadataRepositoryException e )
558         {
559             log.error( e.getMessage(), e );
560             throw new ArchivaRestServiceException( e.getMessage(),
561                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
562         }
563         finally
564         {
565             repositorySession.close();
566         }
567         return Boolean.TRUE;
568     }
569
570     public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
571         throws ArchivaRestServiceException
572     {
573         ProjectVersionMetadata projectVersionMetadata =
574             getProjectMetadata( groupId, artifactId, version, repositoryId );
575
576         if ( projectVersionMetadata == null )
577         {
578             return Boolean.FALSE;
579         }
580
581         GenericMetadataFacet metadataFacet =
582             (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
583
584         if ( metadataFacet != null && metadataFacet.toProperties() != null )
585         {
586             Map<String, String> properties = metadataFacet.toProperties();
587             properties.remove( key );
588             metadataFacet.setAdditionalProperties( properties );
589         }
590         else
591         {
592             return Boolean.TRUE;
593         }
594
595         RepositorySession repositorySession = repositorySessionFactory.createSession();
596
597         try
598         {
599             MetadataRepository metadataRepository = repositorySession.getRepository();
600
601             metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
602
603             repositorySession.save();
604         }
605         catch ( MetadataRepositoryException e )
606         {
607             log.error( e.getMessage(), e );
608             throw new ArchivaRestServiceException( e.getMessage(),
609                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
610         }
611         finally
612         {
613             repositorySession.close();
614         }
615         return Boolean.TRUE;
616     }
617
618     public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
619                                                                  String classifier, String type, String path,
620                                                                  String repositoryId )
621         throws ArchivaRestServiceException
622     {
623         List<String> selectedRepos = getSelectedRepos( repositoryId );
624         try
625         {
626             for ( String repoId : selectedRepos )
627             {
628
629                 ManagedRepositoryContent managedRepositoryContent =
630                     repositoryContentFactory.getManagedRepositoryContent( repoId );
631                 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
632                                                                        StringUtils.isEmpty( type ) ? "jar" : type,
633                                                                        repoId );
634                 File file = managedRepositoryContent.toFile( archivaArtifact );
635                 if ( file.exists() )
636                 {
637                     return readFileEntries( file, path );
638                 }
639             }
640         }
641         catch ( IOException e )
642         {
643             log.error( e.getMessage(), e );
644             throw new ArchivaRestServiceException( e.getMessage(),
645                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
646         }
647         catch ( RepositoryNotFoundException e )
648         {
649             log.error( e.getMessage(), e );
650             throw new ArchivaRestServiceException( e.getMessage(),
651                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
652         }
653         catch ( RepositoryException e )
654         {
655             log.error( e.getMessage(), e );
656             throw new ArchivaRestServiceException( e.getMessage(),
657                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
658         }
659         return Collections.emptyList();
660     }
661
662     public List<ArtifactDownloadInfo> getArtifactDownloadInfos( String groupId, String artifactId, String version,
663                                                                 String repositoryId )
664         throws ArchivaRestServiceException
665     {
666         List<String> selectedRepos = getSelectedRepos( repositoryId );
667
668         List<ArtifactDownloadInfo> artifactDownloadInfos = new ArrayList<ArtifactDownloadInfo>();
669
670         RepositorySession session = repositorySessionFactory.createSession();
671
672         MetadataResolver metadataResolver = session.getResolver();
673
674         try
675         {
676             for ( String repoId : selectedRepos )
677             {
678                 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
679                     metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
680                 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
681
682                 for ( ArtifactMetadata artifact : artifacts )
683                 {
684
685                     ArtifactDownloadInfoBuilder builder =
686                         new ArtifactDownloadInfoBuilder().forArtifactMetadata( artifact ).withManagedRepositoryContent(
687                             repositoryContentFactory.getManagedRepositoryContent( repoId ) );
688                     artifactDownloadInfos.add( builder.build() );
689                 }
690
691             }
692         }
693         catch ( RepositoryException e )
694         {
695             log.error( e.getMessage(), e );
696             throw new ArchivaRestServiceException( e.getMessage(),
697                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
698         }
699         catch ( MetadataResolutionException e )
700         {
701             log.error( e.getMessage(), e );
702             throw new ArchivaRestServiceException( e.getMessage(),
703                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
704         }
705         finally
706         {
707             if ( session != null )
708             {
709                 session.close();
710             }
711         }
712
713         return artifactDownloadInfos;
714     }
715
716     public String getArtifactContentText( String groupId, String artifactId, String version, String classifier,
717                                           String type, String path, String repositoryId )
718         throws ArchivaRestServiceException
719     {
720         List<String> selectedRepos = getSelectedRepos( repositoryId );
721         try
722         {
723             for ( String repoId : selectedRepos )
724             {
725
726                 ManagedRepositoryContent managedRepositoryContent =
727                     repositoryContentFactory.getManagedRepositoryContent( repoId );
728                 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
729                                                                        StringUtils.isEmpty( type ) ? "jar" : type,
730                                                                        repoId );
731                 File file = managedRepositoryContent.toFile( archivaArtifact );
732                 if ( !file.exists() )
733                 {
734                     // 404 ?
735                     return "";
736                 }
737                 if ( StringUtils.isNotBlank( path ) )
738                 {
739                     // zip entry of the path -> path must a real file entry of the archive
740                     JarFile jarFile = new JarFile( file );
741                     ZipEntry zipEntry = jarFile.getEntry( path );
742                     InputStream inputStream = jarFile.getInputStream( zipEntry );
743                     try
744                     {
745                         return IOUtils.toString( inputStream );
746                     }
747                     finally
748                     {
749                         IOUtils.closeQuietly( inputStream );
750                     }
751                 }
752                 return FileUtils.readFileToString( file );
753             }
754         }
755         catch ( IOException e )
756         {
757             log.error( e.getMessage(), e );
758             throw new ArchivaRestServiceException( e.getMessage(),
759                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
760         }
761         catch ( RepositoryNotFoundException e )
762         {
763             log.error( e.getMessage(), e );
764             throw new ArchivaRestServiceException( e.getMessage(),
765                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
766         }
767         catch ( RepositoryException e )
768         {
769             log.error( e.getMessage(), e );
770             throw new ArchivaRestServiceException( e.getMessage(),
771                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
772         }
773         return "";
774     }
775
776     //---------------------------
777     // internals
778     //---------------------------
779
780     protected List<ArtifactContentEntry> readFileEntries( File file, String filterPath )
781         throws IOException
782     {
783         Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<String, ArtifactContentEntry>();
784         int filterDepth = StringUtils.countMatches( filterPath, "/" );
785         /*if ( filterDepth == 0 )
786         {
787             filterDepth = 1;
788         }*/
789         JarFile jarFile = new JarFile( file );
790         try
791         {
792             Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
793             while ( jarEntryEnumeration.hasMoreElements() )
794             {
795                 JarEntry currentEntry = jarEntryEnumeration.nextElement();
796                 String cleanedEntryName =
797                     StringUtils.endsWith( currentEntry.getName(), "/" ) ? StringUtils.substringBeforeLast(
798                         currentEntry.getName(), "/" ) : currentEntry.getName();
799                 String entryRootPath = getRootPath( cleanedEntryName );
800                 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
801                 if ( StringUtils.isEmpty( filterPath ) && !artifactContentEntryMap.containsKey( entryRootPath )
802                     && depth == filterDepth )
803                 {
804
805                     artifactContentEntryMap.put( entryRootPath,
806                                                  new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
807                                                                            depth ) );
808                 }
809                 else
810                 {
811                     if ( StringUtils.startsWith( cleanedEntryName, filterPath ) && ( depth == filterDepth || (
812                         !currentEntry.isDirectory() && depth == filterDepth ) ) )
813                     {
814                         artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
815                                                                                                  !currentEntry.isDirectory(),
816                                                                                                  depth ) );
817                     }
818                 }
819             }
820
821             if ( StringUtils.isNotEmpty( filterPath ) )
822             {
823                 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap =
824                     new HashMap<String, ArtifactContentEntry>();
825
826                 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
827                 {
828                     filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
829                 }
830
831                 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
832                 if ( sorted == null )
833                 {
834                     return Collections.emptyList();
835                 }
836                 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
837                 return sorted;
838             }
839         }
840         finally
841         {
842             if ( jarFile != null )
843             {
844                 jarFile.close();
845             }
846         }
847         List<ArtifactContentEntry> sorted = new ArrayList<ArtifactContentEntry>( artifactContentEntryMap.values() );
848         Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
849         return sorted;
850     }
851
852     private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
853     {
854         int smallestDepth = Integer.MAX_VALUE;
855         Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<Integer, List<ArtifactContentEntry>>();
856         for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
857         {
858
859             ArtifactContentEntry current = entry.getValue();
860
861             if ( current.getDepth() < smallestDepth )
862             {
863                 smallestDepth = current.getDepth();
864             }
865
866             List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
867
868             if ( currentList == null )
869             {
870                 currentList = new ArrayList<ArtifactContentEntry>();
871                 currentList.add( current );
872                 perDepthList.put( current.getDepth(), currentList );
873             }
874             else
875             {
876                 currentList.add( current );
877             }
878
879         }
880
881         return perDepthList.get( smallestDepth );
882     }
883
884     /**
885      * @param path
886      * @return org/apache -> org , org -> org
887      */
888     private String getRootPath( String path )
889     {
890         if ( StringUtils.contains( path, '/' ) )
891         {
892             return StringUtils.substringBefore( path, "/" );
893         }
894         return path;
895     }
896
897     private List<String> getSelectedRepos( String repositoryId )
898         throws ArchivaRestServiceException
899     {
900
901         List<String> selectedRepos = getObservableRepos();
902
903         if ( CollectionUtils.isEmpty( selectedRepos ) )
904         {
905             // FIXME 403 ???
906             return Collections.emptyList();
907         }
908
909         if ( StringUtils.isNotEmpty( repositoryId ) )
910         {
911             // check user has karma on the repository
912             if ( !selectedRepos.contains( repositoryId ) )
913             {
914                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
915                                                        Response.Status.FORBIDDEN.getStatusCode(), null );
916             }
917             selectedRepos = Collections.singletonList( repositoryId );
918         }
919         return selectedRepos;
920     }
921
922
923     private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
924                                        Collection<String> repoIds, String n )
925         throws MetadataResolutionException
926     {
927         Set<String> subNamespaces = new LinkedHashSet<String>();
928         for ( String repoId : repoIds )
929         {
930             subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
931         }
932         if ( subNamespaces.size() != 1 )
933         {
934             log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
935             return n;
936         }
937         else
938         {
939             for ( String repoId : repoIds )
940             {
941                 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
942                 if ( projects != null && !projects.isEmpty() )
943                 {
944                     log.debug( "{} is not collapsible as it has projects", n );
945                     return n;
946                 }
947             }
948             return collapseNamespaces( repositorySession, metadataResolver, repoIds,
949                                        n + "." + subNamespaces.iterator().next() );
950         }
951     }
952 }