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