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