This project has retired. For details please refer to its
Attic page.
DefaultBrowseService xref
1 package org.apache.archiva.rest.services;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.apache.archiva.admin.model.RepositoryAdminException;
22 import org.apache.archiva.admin.model.beans.ManagedRepository;
23 import org.apache.archiva.common.utils.VersionComparator;
24 import org.apache.archiva.common.utils.VersionUtil;
25 import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder;
26 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
27 import org.apache.archiva.maven2.model.Artifact;
28 import org.apache.archiva.maven2.model.TreeEntry;
29 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
30 import org.apache.archiva.metadata.model.ArtifactMetadata;
31 import org.apache.archiva.metadata.model.MetadataFacet;
32 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
33 import org.apache.archiva.metadata.model.ProjectVersionReference;
34 import org.apache.archiva.metadata.repository.MetadataRepository;
35 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
36 import org.apache.archiva.metadata.repository.MetadataResolutionException;
37 import org.apache.archiva.metadata.repository.MetadataResolver;
38 import org.apache.archiva.metadata.repository.RepositorySession;
39 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
40 import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
41 import org.apache.archiva.model.ArchivaArtifact;
42 import org.apache.archiva.model.ArchivaRepositoryMetadata;
43 import org.apache.archiva.proxy.model.RepositoryProxyConnectors;
44 import org.apache.archiva.redback.components.cache.Cache;
45 import org.apache.archiva.repository.ManagedRepositoryContent;
46 import org.apache.archiva.repository.RepositoryContentFactory;
47 import org.apache.archiva.repository.RepositoryException;
48 import org.apache.archiva.repository.RepositoryNotFoundException;
49 import org.apache.archiva.repository.metadata.MetadataTools;
50 import org.apache.archiva.rest.api.model.ArtifactContent;
51 import org.apache.archiva.rest.api.model.ArtifactContentEntry;
52 import org.apache.archiva.rest.api.model.BrowseResult;
53 import org.apache.archiva.rest.api.model.BrowseResultEntry;
54 import org.apache.archiva.rest.api.model.Entry;
55 import org.apache.archiva.rest.api.model.MetadataAddRequest;
56 import org.apache.archiva.rest.api.model.VersionsList;
57 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
58 import org.apache.archiva.rest.api.services.BrowseService;
59 import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
60 import org.apache.archiva.security.ArchivaSecurityException;
61 import org.apache.archiva.xml.XMLException;
62 import org.apache.commons.collections.CollectionUtils;
63 import org.apache.commons.io.FileUtils;
64 import org.apache.commons.io.IOUtils;
65 import org.apache.commons.lang.StringUtils;
66 import org.springframework.stereotype.Service;
67
68 import javax.inject.Inject;
69 import javax.inject.Named;
70 import javax.ws.rs.core.Response;
71 import java.io.File;
72 import java.io.IOException;
73 import java.io.InputStream;
74 import java.util.ArrayList;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.Enumeration;
78 import java.util.HashMap;
79 import java.util.LinkedHashSet;
80 import java.util.List;
81 import java.util.Map;
82 import java.util.Set;
83 import java.util.jar.JarEntry;
84 import java.util.jar.JarFile;
85 import java.util.zip.ZipEntry;
86
87
88
89
90
91 @Service( "browseService#rest" )
92 public class DefaultBrowseService
93 extends AbstractRestService
94 implements BrowseService
95 {
96
97 @Inject
98 private DependencyTreeBuilder dependencyTreeBuilder;
99
100 @Inject
101 private RepositoryContentFactory repositoryContentFactory;
102
103 @Inject
104 @Named( value = "repositoryProxyConnectors#default" )
105 private RepositoryProxyConnectors connectors;
106
107 @Inject
108 @Named( value = "browse#versionMetadata" )
109 private Cache<String, ProjectVersionMetadata> versionMetadataCache;
110
111 @Override
112 public BrowseResult getRootGroups( String repositoryId )
113 throws ArchivaRestServiceException
114 {
115 List<String> selectedRepos = getSelectedRepos( repositoryId );
116
117 Set<String> namespaces = new LinkedHashSet<String>();
118
119
120
121
122 Set<String> namespacesToCollapse = new LinkedHashSet<String>();
123 RepositorySession repositorySession = repositorySessionFactory.createSession();
124 try
125 {
126 MetadataResolver metadataResolver = repositorySession.getResolver();
127
128 for ( String repoId : selectedRepos )
129 {
130 namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
131 }
132 for ( String n : namespacesToCollapse )
133 {
134
135 namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
136 }
137 }
138 catch ( MetadataResolutionException e )
139 {
140 throw new ArchivaRestServiceException( e.getMessage(),
141 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
142 }
143 finally
144 {
145 repositorySession.close();
146 }
147
148 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
149 for ( String namespace : namespaces )
150 {
151 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
152 }
153
154 Collections.sort( browseGroupResultEntries );
155 return new BrowseResult( browseGroupResultEntries );
156 }
157
158 @Override
159 public BrowseResult browseGroupId( String groupId, String repositoryId )
160 throws ArchivaRestServiceException
161 {
162 List<String> selectedRepos = getSelectedRepos( repositoryId );
163
164 Set<String> projects = new LinkedHashSet<>();
165
166 RepositorySession repositorySession = repositorySessionFactory.createSession();
167 Set<String> namespaces;
168 try
169 {
170 MetadataResolver metadataResolver = repositorySession.getResolver();
171
172 Set<String> namespacesToCollapse = new LinkedHashSet<>();
173 for ( String repoId : selectedRepos )
174 {
175 namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
176
177 projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
178 }
179
180
181
182
183 namespaces = new LinkedHashSet<>();
184 for ( String n : namespacesToCollapse )
185 {
186
187 namespaces.add(
188 collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
189 }
190 }
191 catch ( MetadataResolutionException e )
192 {
193 throw new ArchivaRestServiceException( e.getMessage(),
194 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
195 }
196 finally
197 {
198 repositorySession.close();
199 }
200 List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
201 for ( String namespace : namespaces )
202 {
203 browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
204 }
205 for ( String project : projects )
206 {
207 browseGroupResultEntries.add(
208 new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
209 }
210 Collections.sort( browseGroupResultEntries );
211 return new BrowseResult( browseGroupResultEntries );
212
213 }
214
215 @Override
216 public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
217 throws ArchivaRestServiceException
218 {
219 List<String> selectedRepos = getSelectedRepos( repositoryId );
220
221 try
222 {
223 Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
224 return new VersionsList( new ArrayList<>( versions ) );
225 }
226 catch ( MetadataResolutionException e )
227 {
228 throw new ArchivaRestServiceException( e.getMessage(),
229 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
230 }
231
232 }
233
234 private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
235 throws MetadataResolutionException
236
237 {
238 RepositorySession repositorySession = repositorySessionFactory.createSession();
239 try
240 {
241 MetadataResolver metadataResolver = repositorySession.getResolver();
242
243 Set<String> versions = new LinkedHashSet<String>();
244
245 for ( String repoId : selectedRepos )
246 {
247 Collection<String> projectVersions =
248 metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
249 versions.addAll( projectVersions );
250 }
251
252 List<String> sortedVersions = new ArrayList<>( versions );
253
254 Collections.sort( sortedVersions, VersionComparator.getInstance() );
255
256 return sortedVersions;
257 }
258 finally
259 {
260 repositorySession.close();
261 }
262 }
263
264 @Override
265 public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
266 String repositoryId )
267 throws ArchivaRestServiceException
268 {
269 List<String> selectedRepos = getSelectedRepos( repositoryId );
270
271 RepositorySession repositorySession = null;
272 try
273 {
274 repositorySession = repositorySessionFactory.createSession();
275
276 MetadataResolver metadataResolver = repositorySession.getResolver();
277
278 ProjectVersionMetadata versionMetadata = null;
279 for ( String repoId : selectedRepos )
280 {
281 if ( versionMetadata == null || versionMetadata.isIncomplete() )
282 {
283 try
284 {
285 ProjectVersionMetadata versionMetadataTmp =
286 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
287 version );
288
289 if ( versionMetadata == null && versionMetadataTmp != null )
290 {
291 versionMetadata = versionMetadataTmp;
292 }
293
294
295 }
296 catch ( MetadataResolutionException e )
297 {
298 log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
299 groupId, artifactId, repoId, e.getMessage() );
300 }
301 }
302 }
303
304 return versionMetadata;
305 }
306 finally
307 {
308 if ( repositorySession != null )
309 {
310 repositorySession.close();
311 }
312 }
313
314 }
315
316 @Override
317 public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
318 throws ArchivaRestServiceException
319 {
320
321 List<String> selectedRepos = getSelectedRepos( repositoryId );
322
323 RepositorySession repositorySession = null;
324 try
325 {
326
327 Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
328
329 repositorySession = repositorySessionFactory.createSession();
330
331 MetadataResolver metadataResolver = repositorySession.getResolver();
332
333 ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
334
335 MavenProjectFacet mavenFacet = new MavenProjectFacet();
336 mavenFacet.setGroupId( groupId );
337 mavenFacet.setArtifactId( artifactId );
338 sharedModel.addFacet( mavenFacet );
339
340 boolean isFirstVersion = true;
341
342 for ( String version : projectVersions )
343 {
344 ProjectVersionMetadata versionMetadata = null;
345 for ( String repoId : selectedRepos )
346 {
347 if ( versionMetadata == null || versionMetadata.isIncomplete() )
348 {
349 try
350 {
351 ProjectVersionMetadata projectVersionMetadataResolved = null;
352 boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
353 String cacheKey = null;
354 boolean cacheToUpdate = false;
355
356
357 if ( useCache )
358 {
359 cacheKey = repoId + groupId + artifactId + version;
360 projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
361 }
362 if ( useCache && projectVersionMetadataResolved != null )
363 {
364 versionMetadata = projectVersionMetadataResolved;
365 }
366 else
367 {
368 projectVersionMetadataResolved =
369 metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
370 artifactId, version );
371 versionMetadata = projectVersionMetadataResolved;
372 cacheToUpdate = true;
373 }
374
375 if ( useCache && cacheToUpdate )
376 {
377 versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
378 }
379
380 }
381 catch ( MetadataResolutionException e )
382 {
383 log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
384 + artifactId + " in repo " + repoId + ": " + e.getMessage() );
385 }
386 }
387 }
388
389 if ( versionMetadata == null )
390 {
391 continue;
392 }
393
394 if ( isFirstVersion )
395 {
396 sharedModel = versionMetadata;
397 sharedModel.setId( null );
398 }
399 else
400 {
401 MavenProjectFacet versionMetadataMavenFacet =
402 (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
403 if ( versionMetadataMavenFacet != null )
404 {
405 if ( mavenFacet.getPackaging() != null
406 && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
407 versionMetadataMavenFacet.getPackaging() ) )
408 {
409 mavenFacet.setPackaging( null );
410 }
411 }
412
413 if ( StringUtils.isEmpty( sharedModel.getName() )
414 && !StringUtils.isEmpty( versionMetadata.getName() ) )
415 {
416 sharedModel.setName( versionMetadata.getName() );
417 }
418
419 if ( sharedModel.getDescription() != null
420 && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
421 versionMetadata.getDescription() ) )
422 {
423 sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
424 ? versionMetadata.getDescription()
425 : "" );
426 }
427
428 if ( sharedModel.getIssueManagement() != null
429 && versionMetadata.getIssueManagement() != null
430 && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
431 versionMetadata.getIssueManagement().getUrl() ) )
432 {
433 sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
434 }
435
436 if ( sharedModel.getCiManagement() != null
437 && versionMetadata.getCiManagement() != null
438 && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
439 versionMetadata.getCiManagement().getUrl() ) )
440 {
441 sharedModel.setCiManagement( versionMetadata.getCiManagement() );
442 }
443
444 if ( sharedModel.getOrganization() != null
445 && versionMetadata.getOrganization() != null
446 && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
447 versionMetadata.getOrganization().getName() ) )
448 {
449 sharedModel.setOrganization( versionMetadata.getOrganization() );
450 }
451
452 if ( sharedModel.getUrl() != null
453 && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
454 {
455 sharedModel.setUrl( versionMetadata.getUrl() );
456 }
457 }
458
459 isFirstVersion = false;
460 }
461 return sharedModel;
462 }
463 catch ( MetadataResolutionException e )
464 {
465 throw new ArchivaRestServiceException( e.getMessage(),
466 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
467 }
468 finally
469 {
470 if ( repositorySession != null )
471 {
472 repositorySession.close();
473 }
474 }
475 }
476
477 @Override
478 public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
479 throws ArchivaRestServiceException
480 {
481 List<String> selectedRepos = getSelectedRepos( repositoryId );
482
483 try
484 {
485 return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
486 }
487 catch ( Exception e )
488 {
489 log.error( e.getMessage(), e );
490 }
491
492 return Collections.emptyList();
493 }
494
495 @Override
496 public List<ManagedRepository> getUserRepositories()
497 throws ArchivaRestServiceException
498 {
499 try
500 {
501 return userRepositories.getAccessibleRepositories( getPrincipal() );
502 }
503 catch ( ArchivaSecurityException e )
504 {
505 throw new ArchivaRestServiceException( "repositories.read.observable.error",
506 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
507 }
508 }
509
510 @Override
511 public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
512 try
513 {
514 return userRepositories.getManagableRepositories( getPrincipal() );
515 }
516 catch ( ArchivaSecurityException e )
517 {
518 throw new ArchivaRestServiceException( "repositories.read.managable.error",
519 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
520 }
521 }
522
523 @Override
524 public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
525 throws ArchivaRestServiceException
526 {
527 List<ProjectVersionReference> references = new ArrayList<>();
528
529 RepositorySession repositorySession = repositorySessionFactory.createSession();
530 try
531 {
532 MetadataResolver metadataResolver = repositorySession.getResolver();
533 for ( String repoId : getObservableRepos() )
534 {
535
536 references.addAll(
537 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
538 version ) );
539 }
540 }
541 catch ( MetadataResolutionException e )
542 {
543 throw new ArchivaRestServiceException( e.getMessage(),
544 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
545 }
546 finally
547 {
548 repositorySession.close();
549 }
550
551 List<Artifact> artifacts = new ArrayList<>( references.size() );
552
553 for ( ProjectVersionReference projectVersionReference : references )
554 {
555 artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
556 projectVersionReference.getProjectVersion() ) );
557 }
558 return artifacts;
559 }
560
561 @Override
562 public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
563 throws ArchivaRestServiceException
564 {
565 ProjectVersionMetadata projectVersionMetadata =
566 getProjectMetadata( groupId, artifactId, version, repositoryId );
567 if ( projectVersionMetadata == null )
568 {
569 return Collections.emptyList();
570 }
571 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
572
573 if ( metadataFacet == null )
574 {
575 return Collections.emptyList();
576 }
577 Map<String, String> map = metadataFacet.toProperties();
578 List<Entry> entries = new ArrayList<>( map.size() );
579
580 for ( Map.Entry<String, String> entry : map.entrySet() )
581 {
582 entries.add( new Entry( entry.getKey(), entry.getValue() ) );
583 }
584
585 return entries;
586 }
587
588 @Override
589 public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
590 String repositoryId )
591 throws ArchivaRestServiceException
592 {
593 ProjectVersionMetadata projectVersionMetadata =
594 getProjectMetadata( groupId, artifactId, version, repositoryId );
595
596 if ( projectVersionMetadata == null )
597 {
598 return Boolean.FALSE;
599 }
600
601 Map<String, String> properties = new HashMap<>();
602
603 MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
604
605 if ( metadataFacet != null && metadataFacet.toProperties() != null )
606 {
607 properties.putAll( metadataFacet.toProperties() );
608 }
609 else
610 {
611 metadataFacet = new GenericMetadataFacet();
612 }
613
614 properties.put( key, value );
615
616 metadataFacet.fromProperties( properties );
617
618 projectVersionMetadata.addFacet( metadataFacet );
619
620 RepositorySession repositorySession = repositorySessionFactory.createSession();
621
622 try
623 {
624 MetadataRepository metadataRepository = repositorySession.getRepository();
625
626 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
627
628 repositorySession.save();
629 }
630 catch ( MetadataRepositoryException e )
631 {
632 log.error( e.getMessage(), e );
633 throw new ArchivaRestServiceException( e.getMessage(),
634 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
635 }
636 finally
637 {
638 repositorySession.close();
639 }
640 return Boolean.TRUE;
641 }
642
643 @Override
644 public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
645 throws ArchivaRestServiceException
646 {
647 ProjectVersionMetadata projectVersionMetadata =
648 getProjectMetadata( groupId, artifactId, version, repositoryId );
649
650 if ( projectVersionMetadata == null )
651 {
652 return Boolean.FALSE;
653 }
654
655 GenericMetadataFacet metadataFacet =
656 (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
657
658 if ( metadataFacet != null && metadataFacet.toProperties() != null )
659 {
660 Map<String, String> properties = metadataFacet.toProperties();
661 properties.remove( key );
662 metadataFacet.setAdditionalProperties( properties );
663 }
664 else
665 {
666 return Boolean.TRUE;
667 }
668
669 RepositorySession repositorySession = repositorySessionFactory.createSession();
670
671 try
672 {
673 MetadataRepository metadataRepository = repositorySession.getRepository();
674
675 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
676
677 repositorySession.save();
678 }
679 catch ( MetadataRepositoryException e )
680 {
681 log.error( e.getMessage(), e );
682 throw new ArchivaRestServiceException( e.getMessage(),
683 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
684 }
685 finally
686 {
687 repositorySession.close();
688 }
689 return Boolean.TRUE;
690 }
691
692 @Override
693 public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
694 String classifier, String type, String path,
695 String repositoryId )
696 throws ArchivaRestServiceException
697 {
698 List<String> selectedRepos = getSelectedRepos( repositoryId );
699 try
700 {
701 for ( String repoId : selectedRepos )
702 {
703
704 ManagedRepositoryContent managedRepositoryContent =
705 repositoryContentFactory.getManagedRepositoryContent( repoId );
706 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
707 StringUtils.isEmpty( type ) ? "jar" : type,
708 repoId );
709 File file = managedRepositoryContent.toFile( archivaArtifact );
710 if ( file.exists() )
711 {
712 return readFileEntries( file, path, repoId );
713 }
714 }
715 }
716 catch ( IOException e )
717 {
718 log.error( e.getMessage(), e );
719 throw new ArchivaRestServiceException( e.getMessage(),
720 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
721 }
722 catch ( RepositoryNotFoundException e )
723 {
724 log.error( e.getMessage(), e );
725 throw new ArchivaRestServiceException( e.getMessage(),
726 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
727 }
728 catch ( RepositoryException e )
729 {
730 log.error( e.getMessage(), e );
731 throw new ArchivaRestServiceException( e.getMessage(),
732 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
733 }
734 return Collections.emptyList();
735 }
736
737 @Override
738 public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
739 String repositoryId )
740 throws ArchivaRestServiceException
741 {
742 List<String> selectedRepos = getSelectedRepos( repositoryId );
743
744 List<Artifact> artifactDownloadInfos = new ArrayList<>();
745
746 try (RepositorySession session = repositorySessionFactory.createSession())
747 {
748 MetadataResolver metadataResolver = session.getResolver();
749 for ( String repoId : selectedRepos )
750 {
751 List<ArtifactMetadata> artifacts = new ArrayList<>(
752 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
753 Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
754 if ( artifacts != null && !artifacts.isEmpty() )
755 {
756 return buildArtifacts( artifacts, repoId );
757 }
758 }
759 }
760 catch ( MetadataResolutionException e )
761 {
762 log.error( e.getMessage(), e );
763 throw new ArchivaRestServiceException( e.getMessage(),
764 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
765 }
766
767 return artifactDownloadInfos;
768 }
769
770 @Override
771 public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
772 String type, String path, String repositoryId )
773 throws ArchivaRestServiceException
774 {
775 List<String> selectedRepos = getSelectedRepos( repositoryId );
776 try
777 {
778 for ( String repoId : selectedRepos )
779 {
780
781 ManagedRepositoryContent managedRepositoryContent =
782 repositoryContentFactory.getManagedRepositoryContent( repoId );
783 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
784 StringUtils.isEmpty( type ) ? "jar" : type,
785 repoId );
786 File file = managedRepositoryContent.toFile( archivaArtifact );
787 if ( !file.exists() )
788 {
789 log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
790 continue;
791 }
792 if ( StringUtils.isNotBlank( path ) )
793 {
794
795 JarFile jarFile = new JarFile( file );
796 ZipEntry zipEntry = jarFile.getEntry( path );
797 try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
798 {
799 return new ArtifactContent( IOUtils.toString( inputStream ), repoId );
800 }
801 finally
802 {
803 closeQuietly( jarFile );
804 }
805 }
806 return new ArtifactContent( FileUtils.readFileToString( file ), repoId );
807 }
808 }
809 catch ( IOException e )
810 {
811 log.error( e.getMessage(), e );
812 throw new ArchivaRestServiceException( e.getMessage(),
813 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
814 }
815 catch ( RepositoryNotFoundException e )
816 {
817 log.error( e.getMessage(), e );
818 throw new ArchivaRestServiceException( e.getMessage(),
819 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
820 }
821 catch ( RepositoryException e )
822 {
823 log.error( e.getMessage(), e );
824 throw new ArchivaRestServiceException( e.getMessage(),
825 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
826 }
827 log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
828
829 return new ArtifactContent();
830 }
831
832 @Override
833 public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
834 String repositoryId )
835 throws ArchivaRestServiceException
836 {
837 List<String> selectedRepos = getSelectedRepos( repositoryId );
838
839 boolean snapshot = VersionUtil.isSnapshot( version );
840
841 try
842 {
843 for ( String repoId : selectedRepos )
844 {
845
846 ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
847
848 if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
849 && managedRepository.isSnapshots() ) )
850 {
851 continue;
852 }
853 ManagedRepositoryContent managedRepositoryContent =
854 repositoryContentFactory.getManagedRepositoryContent( repoId );
855
856 ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
857 StringUtils.isEmpty( classifier )
858 ? ""
859 : classifier, "jar", repoId );
860 File file = managedRepositoryContent.toFile( archivaArtifact );
861
862 if ( file != null && file.exists() )
863 {
864 return true;
865 }
866
867
868 if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
869 {
870 File metadataFile = new File( file.getParent(), MetadataTools.MAVEN_METADATA );
871 if ( metadataFile.exists() )
872 {
873 try
874 {
875 ArchivaRepositoryMetadata archivaRepositoryMetadata =
876 MavenMetadataReader.read( metadataFile );
877 int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
878 String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
879
880 String timeStampFileName = new StringBuilder( artifactId ).append( '-' )
881 .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) )
882 .append( '-' ).append( timeStamp )
883 .append( '-' ).append( Integer.toString( buildNumber ) )
884 .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) )
885 .append( ".jar" ).toString();
886
887 File timeStampFile = new File( file.getParent(), timeStampFileName );
888 log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.getPath() );
889 if ( timeStampFile.exists() )
890 {
891 return true;
892 }
893 }
894 catch ( XMLException e )
895 {
896 log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
897 }
898 }
899 }
900
901 String path = managedRepositoryContent.toPath( archivaArtifact );
902
903 file = connectors.fetchFromProxies( managedRepositoryContent, path );
904
905 if ( file != null && file.exists() )
906 {
907
908 String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
909 connectors.fetchFromProxies( managedRepositoryContent, pomPath );
910 return true;
911 }
912 }
913 }
914 catch ( RepositoryAdminException e )
915 {
916 log.error( e.getMessage(), e );
917 throw new ArchivaRestServiceException( e.getMessage(),
918 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
919 }
920 catch ( RepositoryException e )
921 {
922 log.error( e.getMessage(), e );
923 throw new ArchivaRestServiceException( e.getMessage(),
924 Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
925 }
926
927 return false;
928 }
929
930 @Override
931 public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
932 throws ArchivaRestServiceException
933 {
934 return artifactAvailable( groupId, artifactId, version, null, repositoryId );
935 }
936
937 @Override
938 public List<Artifact> getArtifacts( String repositoryId )
939 throws ArchivaRestServiceException
940 {
941 RepositorySession repositorySession = repositorySessionFactory.createSession();
942 try
943 {
944 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
945 return buildArtifacts( artifactMetadatas, repositoryId );
946 }
947 catch ( MetadataRepositoryException e )
948 {
949 throw new ArchivaRestServiceException( e.getMessage(), e );
950 }
951 finally
952 {
953 repositorySession.close();
954 }
955 }
956
957 @Override
958 public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
959 throws ArchivaRestServiceException
960 {
961 RepositorySession repositorySession = repositorySessionFactory.createSession();
962 try
963 {
964 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionMetadata( key, value, repositoryId );
965 return buildArtifacts( artifactMetadatas, repositoryId );
966 }
967 catch ( MetadataRepositoryException e )
968 {
969 throw new ArchivaRestServiceException( e.getMessage(), e );
970 }
971 finally
972 {
973 repositorySession.close();
974 }
975 }
976
977 @Override
978 public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
979 throws ArchivaRestServiceException
980 {
981 RepositorySession repositorySession = repositorySessionFactory.createSession();
982 try
983 {
984 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata( key, value, repositoryId );
985 return buildArtifacts( artifactMetadatas, repositoryId );
986 }
987 catch ( MetadataRepositoryException e )
988 {
989 throw new ArchivaRestServiceException( e.getMessage(), e );
990 }
991 finally
992 {
993 repositorySession.close();
994 }
995 }
996
997 @Override
998 public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
999 throws ArchivaRestServiceException
1000 {
1001 RepositorySession repositorySession = repositorySessionFactory.createSession();
1002 try
1003 {
1004 List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty( key, value, repositoryId );
1005 return buildArtifacts( artifactMetadatas, repositoryId );
1006 }
1007 catch ( MetadataRepositoryException e )
1008 {
1009 throw new ArchivaRestServiceException( e.getMessage(), e );
1010 }
1011 finally
1012 {
1013 repositorySession.close();
1014 }
1015 }
1016
1017 @Override
1018 public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
1019 throws ArchivaRestServiceException
1020 {
1021 boolean result = true;
1022 for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
1023 {
1024 result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
1025 metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
1026 repositoryId );
1027 if ( !result )
1028 {
1029 break;
1030 }
1031 }
1032 return result;
1033 }
1034
1035 @Override
1036 public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
1037 throws ArchivaRestServiceException
1038 {
1039 RepositorySession repositorySession = repositorySessionFactory.createSession();
1040 try
1041 {
1042 List<ArtifactMetadata> artifactMetadatas =
1043 repositorySession.getRepository().searchArtifacts( text, repositoryId, exact == null ? false : exact );
1044 return buildArtifacts( artifactMetadatas, repositoryId );
1045 }
1046 catch ( MetadataRepositoryException e )
1047 {
1048 throw new ArchivaRestServiceException( e.getMessage(), e );
1049 }
1050 finally
1051 {
1052 repositorySession.close();
1053 }
1054 }
1055
1056 @Override
1057 public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
1058 throws ArchivaRestServiceException
1059 {
1060 RepositorySession repositorySession = repositorySessionFactory.createSession();
1061 try
1062 {
1063 List<ArtifactMetadata> artifactMetadatas =
1064 repositorySession.getRepository().searchArtifacts( key, text, repositoryId, exact == null ? false : exact );
1065 return buildArtifacts( artifactMetadatas, repositoryId );
1066 }
1067 catch ( MetadataRepositoryException e )
1068 {
1069 throw new ArchivaRestServiceException( e.getMessage(), e );
1070 }
1071 finally
1072 {
1073 repositorySession.close();
1074 }
1075 }
1076
1077
1078
1079
1080
1081 private void closeQuietly( JarFile jarFile )
1082 {
1083 if ( jarFile != null )
1084 {
1085 try
1086 {
1087 jarFile.close();
1088 }
1089 catch ( IOException e )
1090 {
1091 log.warn( "ignore error closing jarFile {}", jarFile.getName() );
1092 }
1093 }
1094 }
1095
1096 protected List<ArtifactContentEntry> readFileEntries(final File file, final String filterPath, final String repoId )
1097 throws IOException
1098 {
1099 String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
1100 StringUtils.substringAfter(filterPath, "/") : filterPath);
1101 Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
1102 int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
1103 if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
1104 filterDepth++;
1105 }
1106 JarFile jarFile = new JarFile( file );
1107 try
1108 {
1109 Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
1110 while ( jarEntryEnumeration.hasMoreElements() )
1111 {
1112 JarEntry currentEntry = jarEntryEnumeration.nextElement();
1113 String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ?
1114 StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
1115 String entryRootPath = getRootPath( cleanedEntryName );
1116 int depth = StringUtils.countMatches( cleanedEntryName, "/" );
1117 if ( StringUtils.isEmpty( cleanedfilterPath )
1118 && !artifactContentEntryMap.containsKey( entryRootPath )
1119 && depth == filterDepth )
1120 {
1121
1122 artifactContentEntryMap.put( entryRootPath,
1123 new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
1124 depth, repoId ) );
1125 }
1126 else
1127 {
1128 if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath )
1129 && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
1130 {
1131 artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
1132 !currentEntry.isDirectory(),
1133 depth, repoId ) );
1134 }
1135 }
1136 }
1137
1138 if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
1139 {
1140 Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
1141
1142 for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
1143 {
1144 filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
1145 }
1146
1147 List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
1148 if ( sorted == null )
1149 {
1150 return Collections.emptyList();
1151 }
1152 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1153 return sorted;
1154 }
1155 }
1156 finally
1157 {
1158 if ( jarFile != null )
1159 {
1160 jarFile.close();
1161 }
1162 }
1163 List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
1164 Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
1165 return sorted;
1166 }
1167
1168 private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
1169 {
1170 int smallestDepth = Integer.MAX_VALUE;
1171 Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
1172 for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
1173 {
1174
1175 ArtifactContentEntry current = entry.getValue();
1176
1177 if ( current.getDepth() < smallestDepth )
1178 {
1179 smallestDepth = current.getDepth();
1180 }
1181
1182 List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
1183
1184 if ( currentList == null )
1185 {
1186 currentList = new ArrayList<>();
1187 currentList.add( current );
1188 perDepthList.put( current.getDepth(), currentList );
1189 }
1190 else
1191 {
1192 currentList.add( current );
1193 }
1194
1195 }
1196
1197 return perDepthList.get( smallestDepth );
1198 }
1199
1200
1201
1202
1203
1204 private String getRootPath( String path )
1205 {
1206 if ( StringUtils.contains( path, '/' ) )
1207 {
1208 return StringUtils.substringBefore( path, "/" );
1209 }
1210 return path;
1211 }
1212
1213 private List<String> getSelectedRepos( String repositoryId )
1214 throws ArchivaRestServiceException
1215 {
1216
1217 List<String> selectedRepos = getObservableRepos();
1218
1219 if ( CollectionUtils.isEmpty( selectedRepos ) )
1220 {
1221 return Collections.emptyList();
1222 }
1223
1224 if ( StringUtils.isNotEmpty( repositoryId ) )
1225 {
1226
1227 if ( !selectedRepos.contains( repositoryId ) )
1228 {
1229 throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
1230 Response.Status.FORBIDDEN.getStatusCode(), null );
1231 }
1232 selectedRepos = Collections.singletonList( repositoryId );
1233 }
1234 return selectedRepos;
1235 }
1236
1237
1238 private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
1239 Collection<String> repoIds, String n )
1240 throws MetadataResolutionException
1241 {
1242 Set<String> subNamespaces = new LinkedHashSet<String>();
1243 for ( String repoId : repoIds )
1244 {
1245 subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
1246 }
1247 if ( subNamespaces.size() != 1 )
1248 {
1249 log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
1250 return n;
1251 }
1252 else
1253 {
1254 for ( String repoId : repoIds )
1255 {
1256 Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
1257 if ( projects != null && !projects.isEmpty() )
1258 {
1259 log.debug( "{} is not collapsible as it has projects", n );
1260 return n;
1261 }
1262 }
1263 return collapseNamespaces( repositorySession, metadataResolver, repoIds,
1264 n + "." + subNamespaces.iterator().next() );
1265 }
1266 }
1267
1268 public Cache getVersionMetadataCache()
1269 {
1270 return versionMetadataCache;
1271 }
1272
1273 public void setVersionMetadataCache( Cache versionMetadataCache )
1274 {
1275 this.versionMetadataCache = versionMetadataCache;
1276 }
1277 }