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