]> source.dussan.org Git - archiva.git/blob
86182503cbf210cdbd9647558de2b0612d21a20f
[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.MetadataFacet;
26 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
27 import org.apache.archiva.metadata.model.ProjectVersionReference;
28 import org.apache.archiva.metadata.repository.MetadataRepository;
29 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
30 import org.apache.archiva.metadata.repository.MetadataResolutionException;
31 import org.apache.archiva.metadata.repository.MetadataResolver;
32 import org.apache.archiva.metadata.repository.RepositorySession;
33 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
34 import org.apache.archiva.rest.api.model.Artifact;
35 import org.apache.archiva.rest.api.model.BrowseResult;
36 import org.apache.archiva.rest.api.model.BrowseResultEntry;
37 import org.apache.archiva.rest.api.model.Entry;
38 import org.apache.archiva.rest.api.model.TreeEntry;
39 import org.apache.archiva.rest.api.model.VersionsList;
40 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
41 import org.apache.archiva.rest.api.services.BrowseService;
42 import org.apache.archiva.rest.services.utils.TreeDependencyNodeVisitor;
43 import org.apache.archiva.security.ArchivaSecurityException;
44 import org.apache.commons.collections.CollectionUtils;
45 import org.apache.commons.lang.StringUtils;
46 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
47 import org.springframework.stereotype.Service;
48
49 import javax.inject.Inject;
50 import javax.ws.rs.core.Response;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashMap;
55 import java.util.LinkedHashSet;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59
60 /**
61  * @author Olivier Lamy
62  * @since 1.4-M3
63  */
64 @Service( "browseService#rest" )
65 public class DefaultBrowseService
66     extends AbstractRestService
67     implements BrowseService
68 {
69
70     @Inject
71     private DependencyTreeBuilder dependencyTreeBuilder;
72
73     public BrowseResult getRootGroups( String repositoryId )
74         throws ArchivaRestServiceException
75     {
76         List<String> selectedRepos = getObservableRepos();
77         if ( CollectionUtils.isEmpty( selectedRepos ) )
78         {
79             // FIXME 403 ???
80             return new BrowseResult();
81         }
82
83         if ( StringUtils.isNotEmpty( repositoryId ) )
84         {
85             // check user has karma on the repository
86             if ( !selectedRepos.contains( repositoryId ) )
87             {
88                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
89                                                        Response.Status.FORBIDDEN.getStatusCode() );
90             }
91             selectedRepos = Collections.singletonList( repositoryId );
92         }
93
94         Set<String> namespaces = new LinkedHashSet<String>();
95
96         // TODO: this logic should be optional, particularly remembering we want to keep this code simple
97         //       it is located here to avoid the content repository implementation needing to do too much for what
98         //       is essentially presentation code
99         Set<String> namespacesToCollapse;
100         RepositorySession repositorySession = repositorySessionFactory.createSession();
101         try
102         {
103             MetadataResolver metadataResolver = repositorySession.getResolver();
104             namespacesToCollapse = new LinkedHashSet<String>();
105
106             for ( String repoId : selectedRepos )
107             {
108                 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
109             }
110             for ( String n : namespacesToCollapse )
111             {
112                 // TODO: check performance of this
113                 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
114             }
115         }
116         catch ( MetadataResolutionException e )
117         {
118             throw new ArchivaRestServiceException( e.getMessage(),
119                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
120         }
121         finally
122         {
123             repositorySession.close();
124         }
125
126         List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<BrowseResultEntry>( namespaces.size() );
127         for ( String namespace : namespaces )
128         {
129             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
130         }
131
132         Collections.sort( browseGroupResultEntries );
133         return new BrowseResult( browseGroupResultEntries );
134     }
135
136     public BrowseResult browseGroupId( String groupId, String repositoryId )
137         throws ArchivaRestServiceException
138     {
139
140         List<String> selectedRepos = getObservableRepos();
141         if ( CollectionUtils.isEmpty( selectedRepos ) )
142         {
143             // FIXME 403 ???
144             return new BrowseResult();
145         }
146
147         if ( StringUtils.isNotEmpty( repositoryId ) )
148         {
149             // check user has karma on the repository
150             if ( !selectedRepos.contains( repositoryId ) )
151             {
152                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
153                                                        Response.Status.FORBIDDEN.getStatusCode() );
154             }
155             selectedRepos = Collections.singletonList( repositoryId );
156         }
157
158         Set<String> projects = new LinkedHashSet<String>();
159
160         RepositorySession repositorySession = repositorySessionFactory.createSession();
161         Set<String> namespaces;
162         try
163         {
164             MetadataResolver metadataResolver = repositorySession.getResolver();
165
166             Set<String> namespacesToCollapse = new LinkedHashSet<String>();
167             for ( String repoId : selectedRepos )
168             {
169                 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
170
171                 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
172             }
173
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 )
179             {
180                 // TODO: check performance of this
181                 namespaces.add(
182                     collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
183             }
184         }
185         catch ( MetadataResolutionException e )
186         {
187             throw new ArchivaRestServiceException( e.getMessage(),
188                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
189         }
190         finally
191         {
192             repositorySession.close();
193         }
194         List<BrowseResultEntry> browseGroupResultEntries =
195             new ArrayList<BrowseResultEntry>( namespaces.size() + projects.size() );
196         for ( String namespace : namespaces )
197         {
198             browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
199         }
200         for ( String project : projects )
201         {
202             browseGroupResultEntries.add( new BrowseResultEntry( groupId + '.' + project, true ) );
203         }
204         Collections.sort( browseGroupResultEntries );
205         return new BrowseResult( browseGroupResultEntries );
206
207     }
208
209     public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
210         throws ArchivaRestServiceException
211     {
212         List<String> selectedRepos = getObservableRepos();
213         if ( CollectionUtils.isEmpty( selectedRepos ) )
214         {
215             // FIXME 403 ???
216             return new VersionsList();
217         }
218
219         if ( StringUtils.isNotEmpty( repositoryId ) )
220         {
221             // check user has karma on the repository
222             if ( !selectedRepos.contains( repositoryId ) )
223             {
224                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
225                                                        Response.Status.FORBIDDEN.getStatusCode() );
226             }
227             selectedRepos = Collections.singletonList( repositoryId );
228         }
229
230         try
231         {
232             return new VersionsList( new ArrayList<String>( getVersions( selectedRepos, groupId, artifactId ) ) );
233         }
234         catch ( MetadataResolutionException e )
235         {
236             throw new ArchivaRestServiceException( e.getMessage(),
237                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
238         }
239
240     }
241
242     private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
243         throws MetadataResolutionException
244
245     {
246         RepositorySession repositorySession = repositorySessionFactory.createSession();
247         try
248         {
249             MetadataResolver metadataResolver = repositorySession.getResolver();
250
251             Set<String> versions = new LinkedHashSet<String>();
252
253             for ( String repoId : selectedRepos )
254             {
255                 versions.addAll(
256                     metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId ) );
257             }
258
259             List<String> sortedVersions = new ArrayList<String>( versions );
260
261             Collections.sort( sortedVersions, VersionComparator.getInstance() );
262
263             return sortedVersions;
264         }
265         finally
266         {
267             repositorySession.close();
268         }
269     }
270
271     public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
272                                                       String repositoryId )
273         throws ArchivaRestServiceException
274     {
275         List<String> selectedRepos = getObservableRepos();
276
277         if ( CollectionUtils.isEmpty( selectedRepos ) )
278         {
279             // FIXME 403 ???
280             return null;
281         }
282
283         if ( StringUtils.isNotEmpty( repositoryId ) )
284         {
285             // check user has karma on the repository
286             if ( !selectedRepos.contains( repositoryId ) )
287             {
288                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
289                                                        Response.Status.FORBIDDEN.getStatusCode() );
290             }
291             selectedRepos = Collections.singletonList( repositoryId );
292         }
293
294         RepositorySession repositorySession = null;
295         try
296         {
297             repositorySession = repositorySessionFactory.createSession();
298
299             MetadataResolver metadataResolver = repositorySession.getResolver();
300
301             ProjectVersionMetadata versionMetadata = null;
302             for ( String repoId : selectedRepos )
303             {
304                 if ( versionMetadata == null || versionMetadata.isIncomplete() )
305                 {
306                     try
307                     {
308                         versionMetadata =
309                             metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
310                                                                     version );
311                     }
312                     catch ( MetadataResolutionException e )
313                     {
314                         log.error(
315                             "Skipping invalid metadata while compiling shared model for " + groupId + ":" + artifactId
316                                 + " in repo " + repoId + ": " + e.getMessage() );
317                     }
318                 }
319             }
320
321             return versionMetadata;
322         }
323         finally
324         {
325             if ( repositorySession != null )
326             {
327                 repositorySession.close();
328             }
329         }
330
331     }
332
333     public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
334         throws ArchivaRestServiceException
335     {
336
337         List<String> selectedRepos = getObservableRepos();
338
339         if ( CollectionUtils.isEmpty( selectedRepos ) )
340         {
341             // FIXME 403 ???
342             return null;
343         }
344
345         if ( StringUtils.isNotEmpty( repositoryId ) )
346         {
347             // check user has karma on the repository
348             if ( !selectedRepos.contains( repositoryId ) )
349             {
350                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
351                                                        Response.Status.FORBIDDEN.getStatusCode() );
352             }
353             selectedRepos = Collections.singletonList( repositoryId );
354         }
355
356         RepositorySession repositorySession = null;
357         try
358         {
359
360             Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
361
362             repositorySession = repositorySessionFactory.createSession();
363
364             MetadataResolver metadataResolver = repositorySession.getResolver();
365
366             ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
367
368             MavenProjectFacet mavenFacet = new MavenProjectFacet();
369             mavenFacet.setGroupId( groupId );
370             mavenFacet.setArtifactId( artifactId );
371             sharedModel.addFacet( mavenFacet );
372
373             boolean isFirstVersion = true;
374
375             for ( String version : projectVersions )
376             {
377                 ProjectVersionMetadata versionMetadata = null;
378                 for ( String repoId : selectedRepos )
379                 {
380                     if ( versionMetadata == null || versionMetadata.isIncomplete() )
381                     {
382                         try
383                         {
384                             versionMetadata =
385                                 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
386                                                                         version );
387                         }
388                         catch ( MetadataResolutionException e )
389                         {
390                             log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
391                                            + artifactId + " in repo " + repoId + ": " + e.getMessage() );
392                         }
393                     }
394                 }
395
396                 if ( versionMetadata == null )
397                 {
398                     continue;
399                 }
400
401                 if ( isFirstVersion )
402                 {
403                     sharedModel = versionMetadata;
404                     sharedModel.setId( null );
405                 }
406                 else
407                 {
408                     MavenProjectFacet versionMetadataMavenFacet =
409                         (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
410                     if ( versionMetadataMavenFacet != null )
411                     {
412                         if ( mavenFacet.getPackaging() != null && !StringUtils.equalsIgnoreCase(
413                             mavenFacet.getPackaging(), versionMetadataMavenFacet.getPackaging() ) )
414                         {
415                             mavenFacet.setPackaging( null );
416                         }
417                     }
418
419                     if ( StringUtils.isEmpty( sharedModel.getName() ) && !StringUtils.isEmpty(
420                         versionMetadata.getName() ) )
421                     {
422                         sharedModel.setName( versionMetadata.getName() );
423                     }
424
425                     if ( sharedModel.getDescription() != null && !StringUtils.equalsIgnoreCase(
426                         sharedModel.getDescription(), versionMetadata.getDescription() ) )
427                     {
428                         sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
429                                                         ? versionMetadata.getDescription()
430                                                         : "" );
431                     }
432
433                     if ( sharedModel.getIssueManagement() != null && versionMetadata.getIssueManagement() != null
434                         && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
435                                                           versionMetadata.getIssueManagement().getUrl() ) )
436                     {
437                         sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
438                     }
439
440                     if ( sharedModel.getCiManagement() != null && versionMetadata.getCiManagement() != null
441                         && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
442                                                           versionMetadata.getCiManagement().getUrl() ) )
443                     {
444                         sharedModel.setCiManagement( versionMetadata.getCiManagement() );
445                     }
446
447                     if ( sharedModel.getOrganization() != null && versionMetadata.getOrganization() != null
448                         && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
449                                                           versionMetadata.getOrganization().getName() ) )
450                     {
451                         sharedModel.setOrganization( versionMetadata.getOrganization() );
452                     }
453
454                     if ( sharedModel.getUrl() != null && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(),
455                                                                                         versionMetadata.getUrl() ) )
456                     {
457                         sharedModel.setUrl( versionMetadata.getUrl() );
458                     }
459                 }
460
461                 isFirstVersion = false;
462             }
463             return sharedModel;
464         }
465         catch ( MetadataResolutionException e )
466         {
467             throw new ArchivaRestServiceException( e.getMessage(),
468                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
469         }
470         finally
471         {
472             if ( repositorySession != null )
473             {
474                 repositorySession.close();
475             }
476         }
477     }
478
479     public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
480         throws ArchivaRestServiceException
481     {
482         List<String> selectedRepos = getObservableRepos();
483
484         if ( CollectionUtils.isEmpty( selectedRepos ) )
485         {
486             // FIXME 403 ???
487             return null;
488         }
489
490         if ( StringUtils.isNotEmpty( repositoryId ) )
491         {
492             // check user has karma on the repository
493             if ( !selectedRepos.contains( repositoryId ) )
494             {
495                 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
496                                                        Response.Status.FORBIDDEN.getStatusCode() );
497             }
498             selectedRepos = Collections.singletonList( repositoryId );
499         }
500
501         List<TreeEntry> treeEntries = new ArrayList<TreeEntry>();
502         TreeDependencyNodeVisitor treeDependencyNodeVisitor = new TreeDependencyNodeVisitor( treeEntries );
503         try
504         {
505             dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version,
506                                                        treeDependencyNodeVisitor );
507         }
508         catch ( DependencyTreeBuilderException e )
509         {
510             throw new ArchivaRestServiceException( e.getMessage(),
511                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
512         }
513         return treeEntries;
514     }
515
516     public List<ManagedRepository> getUserRepositories()
517         throws ArchivaRestServiceException
518     {
519         try
520         {
521             return userRepositories.getAccessibleRepositories( getPrincipal() );
522         }
523         catch ( ArchivaSecurityException e )
524         {
525             throw new ArchivaRestServiceException( "repositories.read.observable.error",
526                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
527         }
528     }
529
530     public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
531         throws ArchivaRestServiceException
532     {
533         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
534         // TODO: what if we get duplicates across repositories?
535         RepositorySession repositorySession = repositorySessionFactory.createSession();
536         try
537         {
538             MetadataResolver metadataResolver = repositorySession.getResolver();
539             for ( String repoId : getObservableRepos() )
540             {
541                 // TODO: what about if we want to see this irrespective of version?
542                 references.addAll(
543                     metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
544                                                                version ) );
545             }
546         }
547         catch ( MetadataResolutionException e )
548         {
549             throw new ArchivaRestServiceException( e.getMessage(),
550                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
551         }
552         finally
553         {
554             repositorySession.close();
555         }
556
557         List<Artifact> artifacts = new ArrayList<Artifact>( references.size() );
558
559         for ( ProjectVersionReference projectVersionReference : references )
560         {
561             artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
562                                          projectVersionReference.getProjectVersion() ) );
563         }
564         return artifacts;
565     }
566
567     public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
568         throws ArchivaRestServiceException
569     {
570         ProjectVersionMetadata projectVersionMetadata =
571             getProjectMetadata( groupId, artifactId, version, repositoryId );
572         if ( projectVersionMetadata == null )
573         {
574             return Collections.emptyList();
575         }
576         MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
577
578         if ( metadataFacet == null )
579         {
580             return Collections.emptyList();
581         }
582         Map<String, String> map = metadataFacet.toProperties();
583         List<Entry> entries = new ArrayList<Entry>( map.size() );
584
585         for ( Map.Entry<String, String> entry : map.entrySet() )
586         {
587             entries.add( new Entry( entry.getKey(), entry.getValue() ) );
588         }
589
590         return entries;
591     }
592
593     public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
594                                 String repositoryId )
595         throws ArchivaRestServiceException
596     {
597         ProjectVersionMetadata projectVersionMetadata =
598             getProjectMetadata( groupId, artifactId, version, repositoryId );
599
600         if ( projectVersionMetadata == null )
601         {
602             return Boolean.FALSE;
603         }
604
605         Map<String, String> properties = new HashMap<String, String>();
606
607         MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
608
609         if ( metadataFacet != null && metadataFacet.toProperties() != null )
610         {
611             properties.putAll( metadataFacet.toProperties() );
612         }
613         else
614         {
615             metadataFacet = new GenericMetadataFacet();
616         }
617
618         properties.put( key, value );
619
620         metadataFacet.fromProperties( properties );
621
622         projectVersionMetadata.addFacet( metadataFacet );
623
624         RepositorySession repositorySession = repositorySessionFactory.createSession();
625
626         try
627         {
628             MetadataRepository metadataRepository = repositorySession.getRepository();
629
630             metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
631
632             repositorySession.save();
633         }
634         catch ( MetadataRepositoryException e )
635         {
636             log.error( e.getMessage(), e );
637             throw new ArchivaRestServiceException( e.getMessage(),
638                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
639         }
640         finally
641         {
642             repositorySession.close();
643         }
644         return Boolean.TRUE;
645     }
646
647     public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
648         throws ArchivaRestServiceException
649     {
650         ProjectVersionMetadata projectVersionMetadata =
651             getProjectMetadata( groupId, artifactId, version, repositoryId );
652
653         if ( projectVersionMetadata == null )
654         {
655             return Boolean.FALSE;
656         }
657
658         GenericMetadataFacet metadataFacet =
659             (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
660
661         if ( metadataFacet != null && metadataFacet.toProperties() != null )
662         {
663             Map<String, String> properties = metadataFacet.toProperties();
664             properties.remove( key );
665             metadataFacet.setAdditionalProperties( properties );
666         }
667         else
668         {
669             return Boolean.TRUE;
670         }
671
672         RepositorySession repositorySession = repositorySessionFactory.createSession();
673
674         try
675         {
676             MetadataRepository metadataRepository = repositorySession.getRepository();
677
678             metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
679
680             repositorySession.save();
681         }
682         catch ( MetadataRepositoryException e )
683         {
684             log.error( e.getMessage(), e );
685             throw new ArchivaRestServiceException( e.getMessage(),
686                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() );
687         }
688         finally
689         {
690             repositorySession.close();
691         }
692         return Boolean.TRUE;
693     }
694
695     //---------------------------
696     // internals
697     //---------------------------
698
699     private List<String> getSortedList( Set<String> set )
700     {
701         List<String> list = new ArrayList<String>( set );
702         Collections.sort( list );
703         return list;
704     }
705
706     private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
707                                        Collection<String> repoIds, String n )
708         throws MetadataResolutionException
709     {
710         Set<String> subNamespaces = new LinkedHashSet<String>();
711         for ( String repoId : repoIds )
712         {
713             subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
714         }
715         if ( subNamespaces.size() != 1 )
716         {
717             log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
718             return n;
719         }
720         else
721         {
722             for ( String repoId : repoIds )
723             {
724                 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
725                 if ( projects != null && !projects.isEmpty() )
726                 {
727                     log.debug( "{} is not collapsible as it has projects", n );
728                     return n;
729                 }
730             }
731             return collapseNamespaces( repositorySession, metadataResolver, repoIds,
732                                        n + "." + subNamespaces.iterator().next() );
733         }
734     }
735 }