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