]> source.dussan.org Git - archiva.git/blob
012b32c2a689c2987f49b26d6ee26fd3b2c3df22
[archiva.git] /
1 package org.apache.archiva.rest.services;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
24 import org.apache.archiva.admin.model.beans.ManagedRepository;
25 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
26 import org.apache.archiva.audit.AuditEvent;
27 import org.apache.archiva.checksum.ChecksumAlgorithm;
28 import org.apache.archiva.checksum.ChecksummedFile;
29 import org.apache.archiva.common.plexusbridge.MavenIndexerUtils;
30 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
31 import org.apache.archiva.common.utils.VersionComparator;
32 import org.apache.archiva.common.utils.VersionUtil;
33 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
34 import org.apache.archiva.maven2.model.Artifact;
35 import org.apache.archiva.metadata.model.ArtifactMetadata;
36 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
37 import org.apache.archiva.metadata.repository.MetadataRepository;
38 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
39 import org.apache.archiva.metadata.repository.MetadataResolutionException;
40 import org.apache.archiva.metadata.repository.RepositorySession;
41 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
42 import org.apache.archiva.model.ArchivaRepositoryMetadata;
43 import org.apache.archiva.model.ArtifactReference;
44 import org.apache.archiva.model.VersionedReference;
45 import org.apache.archiva.redback.authentication.AuthenticationResult;
46 import org.apache.archiva.redback.authorization.AuthorizationException;
47 import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
48 import org.apache.archiva.redback.system.DefaultSecuritySession;
49 import org.apache.archiva.redback.system.SecuritySession;
50 import org.apache.archiva.redback.system.SecuritySystem;
51 import org.apache.archiva.redback.users.User;
52 import org.apache.archiva.redback.users.UserManagerException;
53 import org.apache.archiva.redback.users.UserNotFoundException;
54 import org.apache.archiva.repository.ContentNotFoundException;
55 import org.apache.archiva.repository.ManagedRepositoryContent;
56 import org.apache.archiva.repository.RepositoryContentFactory;
57 import org.apache.archiva.repository.RepositoryException;
58 import org.apache.archiva.repository.RepositoryNotFoundException;
59 import org.apache.archiva.repository.events.RepositoryListener;
60 import org.apache.archiva.repository.metadata.MetadataTools;
61 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
62 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
63 import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
64 import org.apache.archiva.repository.scanner.RepositoryScanner;
65 import org.apache.archiva.repository.scanner.RepositoryScannerException;
66 import org.apache.archiva.rest.api.model.ArtifactTransferRequest;
67 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
68 import org.apache.archiva.rest.api.services.RepositoriesService;
69 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
70 import org.apache.archiva.scheduler.indexing.ArchivaIndexingTaskExecutor;
71 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
72 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexException;
73 import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexScheduler;
74 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
75 import org.apache.archiva.security.ArchivaSecurityException;
76 import org.apache.archiva.security.common.ArchivaRoleConstants;
77 import org.apache.archiva.xml.XMLException;
78 import org.apache.commons.io.FilenameUtils;
79 import org.apache.commons.io.IOUtils;
80 import org.apache.commons.lang.StringUtils;
81 import org.apache.maven.index.context.IndexingContext;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84 import org.springframework.stereotype.Service;
85
86 import javax.inject.Inject;
87 import javax.inject.Named;
88 import javax.ws.rs.core.Response;
89 import java.io.File;
90 import java.io.FileInputStream;
91 import java.io.FileOutputStream;
92 import java.io.IOException;
93 import java.text.DateFormat;
94 import java.text.SimpleDateFormat;
95 import java.util.ArrayList;
96 import java.util.Calendar;
97 import java.util.Collection;
98 import java.util.Collections;
99 import java.util.Date;
100 import java.util.List;
101 import java.util.Set;
102 import java.util.TimeZone;
103
104 /**
105  * @author Olivier Lamy
106  * @since 1.4-M1
107  */
108 @Service( "repositoriesService#rest" )
109 public class DefaultRepositoriesService
110     extends AbstractRestService
111     implements RepositoriesService
112 {
113     private Logger log = LoggerFactory.getLogger( getClass() );
114
115     @Inject
116     @Named( value = "taskExecutor#indexing" )
117     private ArchivaIndexingTaskExecutor archivaIndexingTaskExecutor;
118
119     @Inject
120     private ManagedRepositoryAdmin managedRepositoryAdmin;
121
122     @Inject
123     private PlexusSisuBridge plexusSisuBridge;
124
125     @Inject
126     private MavenIndexerUtils mavenIndexerUtils;
127
128     @Inject
129     private SecuritySystem securitySystem;
130
131     @Inject
132     private RepositoryContentFactory repositoryFactory;
133
134     @Inject
135     @Named( value = "archivaTaskScheduler#repository" )
136     private ArchivaTaskScheduler scheduler;
137
138     @Inject
139     private DownloadRemoteIndexScheduler downloadRemoteIndexScheduler;
140
141     @Inject
142     @Named( value = "repositorySessionFactory" )
143     protected RepositorySessionFactory repositorySessionFactory;
144
145     @Inject
146     protected List<RepositoryListener> listeners = new ArrayList<RepositoryListener>();
147
148     @Inject
149     private RepositoryScanner repoScanner;
150
151     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
152
153     public Boolean scanRepository( String repositoryId, boolean fullScan )
154     {
155         return doScanRepository( repositoryId, fullScan );
156     }
157
158     public Boolean alreadyScanning( String repositoryId )
159     {
160         return repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId );
161     }
162
163     public Boolean removeScanningTaskFromQueue( String repositoryId )
164     {
165         RepositoryTask task = new RepositoryTask();
166         task.setRepositoryId( repositoryId );
167         try
168         {
169             return repositoryTaskScheduler.unQueueTask( task );
170         }
171         catch ( TaskQueueException e )
172         {
173             log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
174             return false;
175         }
176     }
177
178     public Boolean scanRepositoryNow( String repositoryId, boolean fullScan )
179         throws ArchivaRestServiceException
180     {
181
182         try
183         {
184             ManagedRepository repository = managedRepositoryAdmin.getManagedRepository( repositoryId );
185
186             IndexingContext context = managedRepositoryAdmin.createIndexContext( repository );
187
188             ArtifactIndexingTask task =
189                 new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, context );
190
191             task.setExecuteOnEntireRepo( true );
192             task.setOnlyUpdate( !fullScan );
193
194             archivaIndexingTaskExecutor.executeTask( task );
195             return Boolean.TRUE;
196         }
197         catch ( Exception e )
198         {
199             log.error( e.getMessage(), e );
200             throw new ArchivaRestServiceException( e.getMessage(), e );
201         }
202     }
203
204     public Boolean scheduleDownloadRemoteIndex( String repositoryId, boolean now, boolean fullDownload )
205         throws ArchivaRestServiceException
206     {
207         try
208         {
209             downloadRemoteIndexScheduler.scheduleDownloadRemote( repositoryId, now, fullDownload );
210         }
211         catch ( DownloadRemoteIndexException e )
212         {
213             log.error( e.getMessage(), e );
214             throw new ArchivaRestServiceException( e.getMessage(), e );
215         }
216         return Boolean.TRUE;
217     }
218
219     public Boolean copyArtifact( ArtifactTransferRequest artifactTransferRequest )
220         throws ArchivaRestServiceException
221     {
222         // check parameters
223         String userName = getAuditInformation().getUser().getUsername();
224         if ( StringUtils.isBlank( userName ) )
225         {
226             throw new ArchivaRestServiceException( "copyArtifact call: userName not found", null );
227         }
228
229         if ( StringUtils.isBlank( artifactTransferRequest.getRepositoryId() ) )
230         {
231             throw new ArchivaRestServiceException( "copyArtifact call: sourceRepositoryId cannot be null", null );
232         }
233
234         if ( StringUtils.isBlank( artifactTransferRequest.getTargetRepositoryId() ) )
235         {
236             throw new ArchivaRestServiceException( "copyArtifact call: targetRepositoryId cannot be null", null );
237         }
238
239         ManagedRepository source = null;
240         try
241         {
242             source = managedRepositoryAdmin.getManagedRepository( artifactTransferRequest.getRepositoryId() );
243         }
244         catch ( RepositoryAdminException e )
245         {
246             throw new ArchivaRestServiceException( e.getMessage(), e );
247         }
248
249         if ( source == null )
250         {
251             throw new ArchivaRestServiceException(
252                 "cannot find repository with id " + artifactTransferRequest.getRepositoryId(), null );
253         }
254
255         ManagedRepository target = null;
256         try
257         {
258             target = managedRepositoryAdmin.getManagedRepository( artifactTransferRequest.getTargetRepositoryId() );
259         }
260         catch ( RepositoryAdminException e )
261         {
262             throw new ArchivaRestServiceException( e.getMessage(), e );
263         }
264
265         if ( target == null )
266         {
267             throw new ArchivaRestServiceException(
268                 "cannot find repository with id " + artifactTransferRequest.getTargetRepositoryId(), null );
269         }
270
271         if ( StringUtils.isBlank( artifactTransferRequest.getGroupId() ) )
272         {
273             throw new ArchivaRestServiceException( "groupId is mandatory", null );
274         }
275
276         if ( StringUtils.isBlank( artifactTransferRequest.getArtifactId() ) )
277         {
278             throw new ArchivaRestServiceException( "artifactId is mandatory", null );
279         }
280
281         if ( StringUtils.isBlank( artifactTransferRequest.getVersion() ) )
282         {
283             throw new ArchivaRestServiceException( "version is mandatory", null );
284         }
285
286         if ( VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
287         {
288             throw new ArchivaRestServiceException( "copy of SNAPSHOT not supported", null );
289         }
290
291         // end check parameters
292
293         User user = null;
294         try
295         {
296             user = securitySystem.getUserManager().findUser( userName );
297         }
298         catch ( UserNotFoundException e )
299         {
300             throw new ArchivaRestServiceException( "user " + userName + " not found", e );
301         }
302         catch ( UserManagerException e )
303         {
304             throw new ArchivaRestServiceException( "ArchivaRestServiceException:" + e.getMessage(), e );
305         }
306
307         // check karma on source : read
308         AuthenticationResult authn = new AuthenticationResult( true, userName, null );
309         SecuritySession securitySession = new DefaultSecuritySession( authn, user );
310         try
311         {
312             boolean authz =
313                 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
314                                              artifactTransferRequest.getRepositoryId() );
315             if ( !authz )
316             {
317                 throw new ArchivaRestServiceException(
318                     "not authorized to access repo:" + artifactTransferRequest.getRepositoryId(), null );
319             }
320         }
321         catch ( AuthorizationException e )
322         {
323             log.error( "error reading permission: " + e.getMessage(), e );
324             throw new ArchivaRestServiceException( e.getMessage(), e );
325         }
326
327         // check karma on target: write
328         try
329         {
330             boolean authz =
331                 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
332                                              artifactTransferRequest.getTargetRepositoryId() );
333             if ( !authz )
334             {
335                 throw new ArchivaRestServiceException(
336                     "not authorized to write to repo:" + artifactTransferRequest.getTargetRepositoryId(), null );
337             }
338         }
339         catch ( AuthorizationException e )
340         {
341             log.error( "error reading permission: " + e.getMessage(), e );
342             throw new ArchivaRestServiceException( e.getMessage(), e );
343         }
344
345         // sounds good we can continue !
346
347         ArtifactReference artifactReference = new ArtifactReference();
348         artifactReference.setArtifactId( artifactTransferRequest.getArtifactId() );
349         artifactReference.setGroupId( artifactTransferRequest.getGroupId() );
350         artifactReference.setVersion( artifactTransferRequest.getVersion() );
351         artifactReference.setClassifier( artifactTransferRequest.getClassifier() );
352         String packaging = StringUtils.trim( artifactTransferRequest.getPackaging() );
353         artifactReference.setType( StringUtils.isEmpty( packaging ) ? "jar" : packaging );
354
355         try
356         {
357
358             ManagedRepositoryContent sourceRepository =
359                 repositoryFactory.getManagedRepositoryContent( artifactTransferRequest.getRepositoryId() );
360
361             String artifactSourcePath = sourceRepository.toPath( artifactReference );
362
363             if ( StringUtils.isEmpty( artifactSourcePath ) )
364             {
365                 log.error( "cannot find artifact " + artifactTransferRequest.toString() );
366                 throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
367                                                        null );
368             }
369
370             File artifactFile = new File( source.getLocation(), artifactSourcePath );
371
372             if ( !artifactFile.exists() )
373             {
374                 log.error( "cannot find artifact " + artifactTransferRequest.toString() );
375                 throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
376                                                        null );
377             }
378
379             ManagedRepositoryContent targetRepository =
380                 repositoryFactory.getManagedRepositoryContent( artifactTransferRequest.getTargetRepositoryId() );
381
382             String artifactPath = targetRepository.toPath( artifactReference );
383
384             int lastIndex = artifactPath.lastIndexOf( '/' );
385
386             String path = artifactPath.substring( 0, lastIndex );
387             File targetPath = new File( target.getLocation(), path );
388
389             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
390             int newBuildNumber = 1;
391             String timestamp = null;
392
393             File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
394             ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
395
396             if ( !targetPath.exists() )
397             {
398                 targetPath.mkdirs();
399             }
400
401             String filename = artifactPath.substring( lastIndex + 1 );
402
403             boolean fixChecksums =
404                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
405
406             File targetFile = new File( targetPath, filename );
407             if ( targetFile.exists() && target.isBlockRedeployments() )
408             {
409                 throw new ArchivaRestServiceException(
410                     "artifact already exists in target repo: " + artifactTransferRequest.getTargetRepositoryId()
411                         + " and redeployment blocked", null );
412             }
413             else
414             {
415                 copyFile( artifactFile, targetPath, filename, fixChecksums );
416                 queueRepositoryTask( target.getId(), targetFile );
417             }
418
419             // copy source pom to target repo
420             String pomFilename = filename;
421             if ( StringUtils.isNotBlank( artifactTransferRequest.getClassifier() ) )
422             {
423                 pomFilename = StringUtils.remove( pomFilename, "-" + artifactTransferRequest.getClassifier() );
424             }
425             pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
426
427             File pomFile = new File(
428                 new File( source.getLocation(), artifactSourcePath.substring( 0, artifactPath.lastIndexOf( '/' ) ) ),
429                 pomFilename );
430
431             if ( pomFile != null && pomFile.length() > 0 )
432             {
433                 copyFile( pomFile, targetPath, pomFilename, fixChecksums );
434                 queueRepositoryTask( target.getId(), new File( targetPath, pomFilename ) );
435
436
437             }
438
439             // explicitly update only if metadata-updater consumer is not enabled!
440             if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
441             {
442                 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
443                                        fixChecksums, artifactTransferRequest );
444
445
446             }
447
448             String msg =
449                 "Artifact \'" + artifactTransferRequest.getGroupId() + ":" + artifactTransferRequest.getArtifactId()
450                     + ":" + artifactTransferRequest.getVersion() + "\' was successfully deployed to repository \'"
451                     + artifactTransferRequest.getTargetRepositoryId() + "\'";
452
453         }
454         catch ( RepositoryException e )
455         {
456             log.error( "RepositoryException: " + e.getMessage(), e );
457             throw new ArchivaRestServiceException( e.getMessage(), e );
458         }
459         catch ( RepositoryAdminException e )
460         {
461             log.error( "RepositoryAdminException: " + e.getMessage(), e );
462             throw new ArchivaRestServiceException( e.getMessage(), e );
463         }
464         catch ( IOException e )
465         {
466             log.error( "IOException: " + e.getMessage(), e );
467             throw new ArchivaRestServiceException( e.getMessage(), e );
468         }
469         return true;
470     }
471
472     private void queueRepositoryTask( String repositoryId, File localFile )
473     {
474         RepositoryTask task = new RepositoryTask();
475         task.setRepositoryId( repositoryId );
476         task.setResourceFile( localFile );
477         task.setUpdateRelatedArtifacts( true );
478         //task.setScanAll( true );
479
480         try
481         {
482             scheduler.queueTask( task );
483         }
484         catch ( TaskQueueException e )
485         {
486             log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
487                            + "']." );
488         }
489     }
490
491     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
492         throws RepositoryMetadataException
493     {
494         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
495         if ( metadataFile.exists() )
496         {
497             try
498             {
499                 metadata = MavenMetadataReader.read( metadataFile );
500             }
501             catch ( XMLException e )
502             {
503                 throw new RepositoryMetadataException( e.getMessage(), e );
504             }
505         }
506         return metadata;
507     }
508
509     private File getMetadata( String targetPath )
510     {
511         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
512
513         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
514     }
515
516     private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
517         throws IOException
518     {
519         FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
520         FileInputStream input = new FileInputStream( sourceFile );
521
522         try
523         {
524             IOUtils.copy( input, out );
525         }
526         finally
527         {
528             IOUtils.closeQuietly( out );
529             IOUtils.closeQuietly( input );
530         }
531
532         if ( fixChecksums )
533         {
534             fixChecksums( new File( targetPath, targetFilename ) );
535         }
536     }
537
538     private void fixChecksums( File file )
539     {
540         ChecksummedFile checksum = new ChecksummedFile( file );
541         checksum.fixChecksums( algorithms );
542     }
543
544     private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
545                                         boolean fixChecksums, ArtifactTransferRequest artifactTransferRequest )
546         throws RepositoryMetadataException
547     {
548         List<String> availableVersions = new ArrayList<String>();
549         String latestVersion = artifactTransferRequest.getVersion();
550
551         File projectDir = new File( targetPath ).getParentFile();
552         File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
553
554         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
555
556         if ( projectMetadataFile.exists() )
557         {
558             availableVersions = projectMetadata.getAvailableVersions();
559
560             Collections.sort( availableVersions, VersionComparator.getInstance() );
561
562             if ( !availableVersions.contains( artifactTransferRequest.getVersion() ) )
563             {
564                 availableVersions.add( artifactTransferRequest.getVersion() );
565             }
566
567             latestVersion = availableVersions.get( availableVersions.size() - 1 );
568         }
569         else
570         {
571             availableVersions.add( artifactTransferRequest.getVersion() );
572
573             projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
574             projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
575         }
576
577         if ( projectMetadata.getGroupId() == null )
578         {
579             projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
580         }
581
582         if ( projectMetadata.getArtifactId() == null )
583         {
584             projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
585         }
586
587         projectMetadata.setLatestVersion( latestVersion );
588         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
589         projectMetadata.setAvailableVersions( availableVersions );
590
591         if ( !VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
592         {
593             projectMetadata.setReleasedVersion( latestVersion );
594         }
595
596         RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
597
598         if ( fixChecksums )
599         {
600             fixChecksums( projectMetadataFile );
601         }
602     }
603
604     public Boolean removeProjectVersion( String repositoryId, String namespace, String projectId, String version )
605         throws ArchivaRestServiceException
606     {
607         // if not a generic we can use the standard way to delete artifact
608         if ( !VersionUtil.isGenericSnapshot( version ) )
609         {
610             Artifact artifact = new Artifact( namespace, projectId, version );
611             return deleteArtifact( artifact );
612         }
613
614         if ( StringUtils.isEmpty( repositoryId ) )
615         {
616             throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
617         }
618
619         if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
620         {
621             throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
622         }
623
624         if ( StringUtils.isEmpty( namespace ) )
625         {
626             throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
627         }
628
629         if ( StringUtils.isEmpty( projectId ) )
630         {
631             throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
632         }
633
634         if ( StringUtils.isEmpty( version ) )
635         {
636             throw new ArchivaRestServiceException( "version cannot be null", 400, null );
637         }
638
639         RepositorySession repositorySession = repositorySessionFactory.createSession();
640
641         try
642         {
643             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
644
645             VersionedReference ref = new VersionedReference();
646             ref.setArtifactId( projectId );
647             ref.setGroupId( namespace );
648             ref.setVersion( version );
649
650             repository.deleteVersion( ref );
651
652             /*
653             ProjectReference projectReference = new ProjectReference();
654             projectReference.setGroupId( namespace );
655             projectReference.setArtifactId( projectId );
656
657             repository.getVersions(  )
658             */
659
660             ArtifactReference artifactReference = new ArtifactReference();
661             artifactReference.setGroupId( namespace );
662             artifactReference.setArtifactId( projectId );
663             artifactReference.setVersion( version );
664
665             MetadataRepository metadataRepository = repositorySession.getRepository();
666
667             Set<ArtifactReference> related = repository.getRelatedArtifacts( artifactReference );
668             log.debug( "related: {}", related );
669             for ( ArtifactReference artifactRef : related )
670             {
671                 repository.deleteArtifact( artifactRef );
672             }
673
674             Collection<ArtifactMetadata> artifacts =
675                 metadataRepository.getArtifacts( repositoryId, namespace, projectId, version );
676
677             for ( ArtifactMetadata artifactMetadata : artifacts )
678             {
679                 metadataRepository.removeArtifact( artifactMetadata, version );
680             }
681
682             metadataRepository.removeProjectVersion( repositoryId, namespace, projectId, version );
683         }
684         catch ( MetadataRepositoryException e )
685         {
686             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
687         }
688         catch ( MetadataResolutionException e )
689         {
690             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
691         }
692         catch ( RepositoryException e )
693         {
694             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
695         }
696         finally
697         {
698
699             repositorySession.save();
700
701             repositorySession.close();
702         }
703
704         return Boolean.TRUE;
705     }
706
707     public Boolean deleteArtifact( Artifact artifact )
708         throws ArchivaRestServiceException
709     {
710
711         String repositoryId = artifact.getContext();
712         if ( StringUtils.isEmpty( repositoryId ) )
713         {
714             throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
715         }
716
717         if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
718         {
719             throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
720         }
721
722         if ( artifact == null )
723         {
724             throw new ArchivaRestServiceException( "artifact cannot be null", 400, null );
725         }
726
727         if ( StringUtils.isEmpty( artifact.getGroupId() ) )
728         {
729             throw new ArchivaRestServiceException( "artifact.groupId cannot be null", 400, null );
730         }
731
732         if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
733         {
734             throw new ArchivaRestServiceException( "artifact.artifactId cannot be null", 400, null );
735         }
736
737         // TODO more control on artifact fields
738
739         boolean snapshotVersion =
740             VersionUtil.isSnapshot( artifact.getVersion() ) | VersionUtil.isGenericSnapshot( artifact.getVersion() );
741
742         RepositorySession repositorySession = repositorySessionFactory.createSession();
743         try
744         {
745             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
746
747             TimeZone timezone = TimeZone.getTimeZone( "UTC" );
748             DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
749             fmt.setTimeZone( timezone );
750             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
751
752             VersionedReference ref = new VersionedReference();
753             ref.setArtifactId( artifact.getArtifactId() );
754             ref.setGroupId( artifact.getGroupId() );
755             ref.setVersion( artifact.getVersion() );
756
757             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
758
759             ArtifactReference artifactReference = new ArtifactReference();
760             artifactReference.setArtifactId( artifact.getArtifactId() );
761             artifactReference.setGroupId( artifact.getGroupId() );
762             artifactReference.setVersion( artifact.getVersion() );
763             artifactReference.setClassifier( artifact.getClassifier() );
764             artifactReference.setType( artifact.getPackaging() );
765
766             MetadataRepository metadataRepository = repositorySession.getRepository();
767
768             String path = repository.toMetadataPath( ref );
769
770             if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
771             {
772                 if ( StringUtils.isBlank( artifact.getPackaging() ) )
773                 {
774                     throw new ArchivaRestServiceException( "You must configure a type/packaging when using classifier",
775                                                            400, null );
776                 }
777
778                 repository.deleteArtifact( artifactReference );
779
780             }
781             else
782             {
783
784                 int index = path.lastIndexOf( '/' );
785                 path = path.substring( 0, index );
786                 File targetPath = new File( repoConfig.getLocation(), path );
787
788                 if ( !targetPath.exists() )
789                 {
790                     //throw new ContentNotFoundException(
791                     //    artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() );
792                     log.warn( "targetPath {} not found skip file deletion", targetPath );
793                 }
794
795                 // TODO: this should be in the storage mechanism so that it is all tied together
796                 // delete from file system
797                 if ( !snapshotVersion )
798                 {
799                     repository.deleteVersion( ref );
800                 }
801                 else
802                 {
803                     Set<ArtifactReference> related = repository.getRelatedArtifacts( artifactReference );
804                     log.debug( "related: {}", related );
805                     for ( ArtifactReference artifactRef : related )
806                     {
807                         repository.deleteArtifact( artifactRef );
808                     }
809                 }
810                 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
811                 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
812
813                 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, artifact );
814             }
815             Collection<ArtifactMetadata> artifacts = Collections.emptyList();
816
817             if ( snapshotVersion )
818             {
819                 String baseVersion = VersionUtil.getBaseVersion( artifact.getVersion() );
820                 artifacts =
821                     metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
822                                                      baseVersion );
823             }
824             else
825             {
826                 artifacts =
827                     metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
828                                                      artifact.getVersion() );
829             }
830
831             log.debug( "artifacts: {}", artifacts );
832
833             if ( artifacts.isEmpty() )
834             {
835                 if ( !snapshotVersion )
836                 {
837                     // verify metata repository doesn't contains anymore the version
838                     Collection<String> projectVersions =
839                         metadataRepository.getProjectVersions( repositoryId, artifact.getGroupId(),
840                                                                artifact.getArtifactId() );
841
842                     if ( projectVersions.contains( artifact.getVersion() ) )
843                     {
844                         log.warn( "artifact not found when deleted but version still here ! so force cleanup" );
845                         metadataRepository.removeProjectVersion( repositoryId, artifact.getGroupId(),
846                                                                  artifact.getArtifactId(), artifact.getVersion() );
847                     }
848
849                 }
850             }
851
852             for ( ArtifactMetadata artifactMetadata : artifacts )
853             {
854
855                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
856                 if ( artifactMetadata.getVersion().equals( artifact.getVersion() ) )
857                 {
858                     if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
859                     {
860                         if ( StringUtils.isBlank( artifact.getPackaging() ) )
861                         {
862                             throw new ArchivaRestServiceException(
863                                 "You must configure a type/packaging when using classifier", 400, null );
864                         }
865                         // cleanup facet which contains classifier information
866                         MavenArtifactFacet mavenArtifactFacet =
867                             (MavenArtifactFacet) artifactMetadata.getFacet( MavenArtifactFacet.FACET_ID );
868
869                         if ( StringUtils.equals( artifact.getClassifier(), mavenArtifactFacet.getClassifier() ) )
870                         {
871                             artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
872                             String groupId = artifact.getGroupId(), artifactId = artifact.getArtifactId(), version =
873                                 artifact.getVersion();
874                             MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet();
875                             mavenArtifactFacetToCompare.setClassifier( artifact.getClassifier() );
876                             metadataRepository.removeArtifact( repositoryId, groupId, artifactId, version,
877                                                                mavenArtifactFacetToCompare );
878                             metadataRepository.save();
879                         }
880
881                     }
882                     else
883                     {
884                         if ( snapshotVersion )
885                         {
886                             metadataRepository.removeArtifact( artifactMetadata,
887                                                                VersionUtil.getBaseVersion( artifact.getVersion() ) );
888                         }
889                         else
890                         {
891                             metadataRepository.removeArtifact( artifactMetadata.getRepositoryId(),
892                                                                artifactMetadata.getNamespace(),
893                                                                artifactMetadata.getProject(), artifact.getVersion(),
894                                                                artifactMetadata.getId() );
895                         }
896                     }
897                     // TODO: move into the metadata repository proper - need to differentiate attachment of
898                     //       repository metadata to an artifact
899                     for ( RepositoryListener listener : listeners )
900                     {
901                         listener.deleteArtifact( metadataRepository, repository.getId(),
902                                                  artifactMetadata.getNamespace(), artifactMetadata.getProject(),
903                                                  artifactMetadata.getVersion(), artifactMetadata.getId() );
904                     }
905
906                     triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
907                 }
908             }
909         }
910         catch ( ContentNotFoundException e )
911         {
912             throw new ArchivaRestServiceException( "Artifact does not exist: " + e.getMessage(), 400, e );
913         }
914         catch ( RepositoryNotFoundException e )
915         {
916             throw new ArchivaRestServiceException( "Target repository cannot be found: " + e.getMessage(), 400, e );
917         }
918         catch ( RepositoryException e )
919         {
920             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
921         }
922         catch ( MetadataResolutionException e )
923         {
924             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
925         }
926         catch ( MetadataRepositoryException e )
927         {
928             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
929         }
930         catch ( RepositoryAdminException e )
931         {
932             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(), 500, e );
933         }
934         finally
935         {
936
937             repositorySession.save();
938
939             repositorySession.close();
940         }
941         return Boolean.TRUE;
942     }
943
944     public Boolean deleteGroupId( String groupId, String repositoryId )
945         throws ArchivaRestServiceException
946     {
947         if ( StringUtils.isEmpty( repositoryId ) )
948         {
949             throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
950         }
951
952         if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
953         {
954             throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
955         }
956
957         if ( StringUtils.isEmpty( groupId ) )
958         {
959             throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
960         }
961
962         RepositorySession repositorySession = repositorySessionFactory.createSession();
963
964         try
965         {
966             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
967
968             repository.deleteGroupId( groupId );
969
970             MetadataRepository metadataRepository = repositorySession.getRepository();
971
972             metadataRepository.removeNamespace( repositoryId, groupId );
973
974             metadataRepository.save();
975         }
976         catch ( MetadataRepositoryException e )
977         {
978             log.error( e.getMessage(), e );
979             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
980         }
981         catch ( RepositoryException e )
982         {
983             log.error( e.getMessage(), e );
984             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
985         }
986         finally
987         {
988
989             repositorySession.close();
990         }
991         return true;
992     }
993
994     public Boolean deleteProject( String groupId, String projectId, String repositoryId )
995         throws ArchivaRestServiceException
996     {
997         if ( StringUtils.isEmpty( repositoryId ) )
998         {
999             throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
1000         }
1001
1002         if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
1003         {
1004             throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
1005         }
1006
1007         if ( StringUtils.isEmpty( groupId ) )
1008         {
1009             throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
1010         }
1011
1012         if ( StringUtils.isEmpty( projectId ) )
1013         {
1014             throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
1015         }
1016
1017         RepositorySession repositorySession = repositorySessionFactory.createSession();
1018
1019         try
1020         {
1021             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
1022
1023             repository.deleteProject( groupId, projectId );
1024         }
1025         catch ( ContentNotFoundException e )
1026         {
1027             log.warn( "skip ContentNotFoundException: {}", e.getMessage() );
1028         }
1029         catch ( RepositoryException e )
1030         {
1031             log.error( e.getMessage(), e );
1032             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1033         }
1034
1035         try
1036         {
1037
1038             MetadataRepository metadataRepository = repositorySession.getRepository();
1039
1040             metadataRepository.removeProject( repositoryId, groupId, projectId );
1041
1042             metadataRepository.save();
1043         }
1044         catch ( MetadataRepositoryException e )
1045         {
1046             log.error( e.getMessage(), e );
1047             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
1048         }
1049         finally
1050         {
1051
1052             repositorySession.close();
1053         }
1054         return true;
1055
1056     }
1057
1058     public Boolean isAuthorizedToDeleteArtifacts( String repoId )
1059         throws ArchivaRestServiceException
1060     {
1061         String userName =
1062             getAuditInformation().getUser() == null ? "guest" : getAuditInformation().getUser().getUsername();
1063
1064         try
1065         {
1066             boolean res = userRepositories.isAuthorizedToDeleteArtifacts( userName, repoId );
1067             return res;
1068         }
1069         catch ( ArchivaSecurityException e )
1070         {
1071             throw new ArchivaRestServiceException( e.getMessage(),
1072                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
1073         }
1074     }
1075
1076     public RepositoryScanStatistics scanRepositoryDirectoriesNow( String repositoryId )
1077         throws ArchivaRestServiceException
1078     {
1079         long sinceWhen = RepositoryScanner.FRESH_SCAN;
1080         try
1081         {
1082             return repoScanner.scan( getManagedRepositoryAdmin().getManagedRepository( repositoryId ), sinceWhen );
1083         }
1084         catch ( RepositoryScannerException e )
1085         {
1086             log.error( e.getMessage(), e );
1087             throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
1088         }
1089         catch ( RepositoryAdminException e )
1090         {
1091             log.error( e.getMessage(), e );
1092             throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
1093         }
1094     }
1095
1096     /**
1097      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
1098      *
1099      * @param metadata
1100      */
1101     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp,
1102                                  Artifact artifact )
1103         throws RepositoryMetadataException
1104     {
1105         List<String> availableVersions = new ArrayList<String>();
1106         String latestVersion = "";
1107
1108         if ( metadataFile.exists() )
1109         {
1110             if ( metadata.getAvailableVersions() != null )
1111             {
1112                 availableVersions = metadata.getAvailableVersions();
1113
1114                 if ( availableVersions.size() > 0 )
1115                 {
1116                     Collections.sort( availableVersions, VersionComparator.getInstance() );
1117
1118                     if ( availableVersions.contains( artifact.getVersion() ) )
1119                     {
1120                         availableVersions.remove( availableVersions.indexOf( artifact.getVersion() ) );
1121                     }
1122                     if ( availableVersions.size() > 0 )
1123                     {
1124                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
1125                     }
1126                 }
1127             }
1128         }
1129
1130         if ( metadata.getGroupId() == null )
1131         {
1132             metadata.setGroupId( artifact.getGroupId() );
1133         }
1134         if ( metadata.getArtifactId() == null )
1135         {
1136             metadata.setArtifactId( artifact.getArtifactId() );
1137         }
1138
1139         if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
1140         {
1141             if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals(
1142                 artifact.getVersion() ) )
1143             {
1144                 metadata.setReleasedVersion( latestVersion );
1145             }
1146         }
1147
1148         metadata.setLatestVersion( latestVersion );
1149         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
1150         metadata.setAvailableVersions( availableVersions );
1151
1152         RepositoryMetadataWriter.write( metadata, metadataFile );
1153         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
1154         checksum.fixChecksums( algorithms );
1155     }
1156
1157     public ManagedRepositoryAdmin getManagedRepositoryAdmin()
1158     {
1159         return managedRepositoryAdmin;
1160     }
1161
1162     public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
1163     {
1164         this.managedRepositoryAdmin = managedRepositoryAdmin;
1165     }
1166
1167     public RepositoryContentFactory getRepositoryFactory()
1168     {
1169         return repositoryFactory;
1170     }
1171
1172     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
1173     {
1174         this.repositoryFactory = repositoryFactory;
1175     }
1176
1177     public RepositorySessionFactory getRepositorySessionFactory()
1178     {
1179         return repositorySessionFactory;
1180     }
1181
1182     public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
1183     {
1184         this.repositorySessionFactory = repositorySessionFactory;
1185     }
1186
1187     public List<RepositoryListener> getListeners()
1188     {
1189         return listeners;
1190     }
1191
1192     public void setListeners( List<RepositoryListener> listeners )
1193     {
1194         this.listeners = listeners;
1195     }
1196
1197     public ArchivaAdministration getArchivaAdministration()
1198     {
1199         return archivaAdministration;
1200     }
1201
1202     public void setArchivaAdministration( ArchivaAdministration archivaAdministration )
1203     {
1204         this.archivaAdministration = archivaAdministration;
1205     }
1206 }
1207
1208