]> source.dussan.org Git - archiva.git/blob
333912f1d03cb8cf58ea501bd0026dc979974ee8
[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 = Collections.emptyList();
732
733             if ( snapshotVersion )
734             {
735                 String baseVersion = VersionUtil.getBaseVersion( artifact.getVersion() );
736                 artifacts =
737                     metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
738                                                      baseVersion );
739             }
740             else
741             {
742                 artifacts =
743                     metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
744                                                      artifact.getVersion() );
745             }
746
747             log.debug( "artifacts: {}", artifacts );
748
749             for ( ArtifactMetadata artifactMetadata : artifacts )
750             {
751
752                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
753                 if ( artifactMetadata.getVersion().equals( artifact.getVersion() ) )
754                 {
755                     if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
756                     {
757                         if ( StringUtils.isBlank( artifact.getPackaging() ) )
758                         {
759                             throw new ArchivaRestServiceException(
760                                 "You must configure a type/packaging when using classifier", 400, null );
761                         }
762                         // cleanup facet which contains classifier information
763                         MavenArtifactFacet mavenArtifactFacet =
764                             (MavenArtifactFacet) artifactMetadata.getFacet( MavenArtifactFacet.FACET_ID );
765
766                         if ( StringUtils.equals( artifact.getClassifier(), mavenArtifactFacet.getClassifier() ) )
767                         {
768                             artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
769                             String groupId = artifact.getGroupId(), artifactId = artifact.getArtifactId(), version =
770                                 artifact.getVersion();
771                             //metadataRepository.updateArtifact( repositoryId, groupId, artifactId, version,
772                             //                                   artifactMetadata );
773                             // String repositoryId, String namespace, String project, String version, String projectId, MetadataFacet metadataFacet
774                             MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet();
775                             mavenArtifactFacetToCompare.setClassifier( artifact.getClassifier() );
776                             metadataRepository.removeArtifact( repositoryId, groupId, artifactId, version,
777                                                                mavenArtifactFacetToCompare );
778                             metadataRepository.save();
779                         }
780
781                     }
782                     else
783                     {
784                         if ( snapshotVersion )
785                         {
786                             metadataRepository.removeArtifact( artifactMetadata,
787                                                                VersionUtil.getBaseVersion( artifact.getVersion() ) );
788                         }
789                         else
790                         {
791                             metadataRepository.removeArtifact( artifactMetadata.getRepositoryId(),
792                                                                artifactMetadata.getNamespace(),
793                                                                artifactMetadata.getProject(), artifact.getVersion(),
794                                                                artifactMetadata.getId() );
795                         }
796                     }
797                     // TODO: move into the metadata repository proper - need to differentiate attachment of
798                     //       repository metadata to an artifact
799                     for ( RepositoryListener listener : listeners )
800                     {
801                         listener.deleteArtifact( metadataRepository, repository.getId(),
802                                                  artifactMetadata.getNamespace(), artifactMetadata.getProject(),
803                                                  artifactMetadata.getVersion(), artifactMetadata.getId() );
804                     }
805
806                     triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
807                 }
808             }
809
810
811         }
812         catch ( ContentNotFoundException e )
813         {
814             throw new ArchivaRestServiceException( "Artifact does not exist: " + e.getMessage(), 400, e );
815         }
816         catch ( RepositoryNotFoundException e )
817         {
818             throw new ArchivaRestServiceException( "Target repository cannot be found: " + e.getMessage(), 400, e );
819         }
820         catch ( RepositoryException e )
821         {
822             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
823         }
824         catch ( MetadataResolutionException e )
825         {
826             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
827         }
828         catch ( MetadataRepositoryException e )
829         {
830             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
831         }
832         catch ( RepositoryAdminException e )
833         {
834             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(), 500, e );
835         }
836         finally
837         {
838
839             repositorySession.save();
840
841             repositorySession.close();
842         }
843         return Boolean.TRUE;
844     }
845
846     public Boolean deleteGroupId( String groupId, String repositoryId )
847         throws ArchivaRestServiceException
848     {
849         if ( StringUtils.isEmpty( repositoryId ) )
850         {
851             throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
852         }
853
854         if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
855         {
856             throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
857         }
858
859         if ( StringUtils.isEmpty( groupId ) )
860         {
861             throw new ArchivaRestServiceException( "artifact.groupId cannot be null", 400, null );
862         }
863
864         try
865         {
866             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
867
868             repository.deleteGroupId( groupId );
869
870         }
871         catch ( RepositoryException e )
872         {
873             log.error( e.getMessage(), e );
874             throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
875         }
876         return true;
877     }
878
879     public Boolean isAuthorizedToDeleteArtifacts( String repoId )
880         throws ArchivaRestServiceException
881     {
882         String userName =
883             getAuditInformation().getUser() == null ? "guest" : getAuditInformation().getUser().getUsername();
884
885         try
886         {
887             boolean res = userRepositories.isAuthorizedToDeleteArtifacts( userName, repoId );
888             return res;
889         }
890         catch ( ArchivaSecurityException e )
891         {
892             throw new ArchivaRestServiceException( e.getMessage(),
893                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
894         }
895     }
896
897     public RepositoryScanStatistics scanRepositoryDirectoriesNow( String repositoryId )
898         throws ArchivaRestServiceException
899     {
900         long sinceWhen = RepositoryScanner.FRESH_SCAN;
901         try
902         {
903             return repoScanner.scan( getManagedRepositoryAdmin().getManagedRepository( repositoryId ), sinceWhen );
904         }
905         catch ( RepositoryScannerException e )
906         {
907             log.error( e.getMessage(), e );
908             throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
909         }
910         catch ( RepositoryAdminException e )
911         {
912             log.error( e.getMessage(), e );
913             throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
914         }
915     }
916
917     /**
918      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
919      *
920      * @param metadata
921      */
922     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp,
923                                  Artifact artifact )
924         throws RepositoryMetadataException
925     {
926         List<String> availableVersions = new ArrayList<String>();
927         String latestVersion = "";
928
929         if ( metadataFile.exists() )
930         {
931             if ( metadata.getAvailableVersions() != null )
932             {
933                 availableVersions = metadata.getAvailableVersions();
934
935                 if ( availableVersions.size() > 0 )
936                 {
937                     Collections.sort( availableVersions, VersionComparator.getInstance() );
938
939                     if ( availableVersions.contains( artifact.getVersion() ) )
940                     {
941                         availableVersions.remove( availableVersions.indexOf( artifact.getVersion() ) );
942                     }
943                     if ( availableVersions.size() > 0 )
944                     {
945                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
946                     }
947                 }
948             }
949         }
950
951         if ( metadata.getGroupId() == null )
952         {
953             metadata.setGroupId( artifact.getGroupId() );
954         }
955         if ( metadata.getArtifactId() == null )
956         {
957             metadata.setArtifactId( artifact.getArtifactId() );
958         }
959
960         if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
961         {
962             if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals(
963                 artifact.getVersion() ) )
964             {
965                 metadata.setReleasedVersion( latestVersion );
966             }
967         }
968
969         metadata.setLatestVersion( latestVersion );
970         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
971         metadata.setAvailableVersions( availableVersions );
972
973         RepositoryMetadataWriter.write( metadata, metadataFile );
974         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
975         checksum.fixChecksums( algorithms );
976     }
977
978     public ManagedRepositoryAdmin getManagedRepositoryAdmin()
979     {
980         return managedRepositoryAdmin;
981     }
982
983     public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
984     {
985         this.managedRepositoryAdmin = managedRepositoryAdmin;
986     }
987
988     public RepositoryContentFactory getRepositoryFactory()
989     {
990         return repositoryFactory;
991     }
992
993     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
994     {
995         this.repositoryFactory = repositoryFactory;
996     }
997
998     public RepositorySessionFactory getRepositorySessionFactory()
999     {
1000         return repositorySessionFactory;
1001     }
1002
1003     public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
1004     {
1005         this.repositorySessionFactory = repositorySessionFactory;
1006     }
1007
1008     public List<RepositoryListener> getListeners()
1009     {
1010         return listeners;
1011     }
1012
1013     public void setListeners( List<RepositoryListener> listeners )
1014     {
1015         this.listeners = listeners;
1016     }
1017
1018     public ArchivaAdministration getArchivaAdministration()
1019     {
1020         return archivaAdministration;
1021     }
1022
1023     public void setArchivaAdministration( ArchivaAdministration archivaAdministration )
1024     {
1025         this.archivaAdministration = archivaAdministration;
1026     }
1027 }
1028
1029