1 package org.apache.archiva.rest.services;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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.checksum.ChecksumAlgorithm;
27 import org.apache.archiva.checksum.ChecksummedFile;
28 import org.apache.archiva.common.plexusbridge.MavenIndexerUtils;
29 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
30 import org.apache.archiva.common.utils.VersionComparator;
31 import org.apache.archiva.common.utils.VersionUtil;
32 import org.apache.archiva.model.ArchivaRepositoryMetadata;
33 import org.apache.archiva.model.ArtifactReference;
34 import org.apache.archiva.repository.ManagedRepositoryContent;
35 import org.apache.archiva.repository.RepositoryContentFactory;
36 import org.apache.archiva.repository.RepositoryException;
37 import org.apache.archiva.repository.metadata.MetadataTools;
38 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
39 import org.apache.archiva.repository.metadata.RepositoryMetadataReader;
40 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
41 import org.apache.archiva.rest.api.model.ArtifactTransferRequest;
42 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
43 import org.apache.archiva.rest.api.services.RepositoriesService;
44 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
45 import org.apache.archiva.scheduler.indexing.ArchivaIndexingTaskExecutor;
46 import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
47 import org.apache.archiva.scheduler.repository.RepositoryArchivaTaskScheduler;
48 import org.apache.archiva.scheduler.repository.RepositoryTask;
49 import org.apache.archiva.security.common.ArchivaRoleConstants;
50 import org.apache.commons.io.FilenameUtils;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang.StringUtils;
53 import org.apache.maven.index.NexusIndexer;
54 import org.apache.maven.index.context.IndexCreator;
55 import org.apache.maven.index.context.IndexingContext;
56 import org.codehaus.plexus.redback.authentication.AuthenticationResult;
57 import org.codehaus.plexus.redback.authorization.AuthorizationException;
58 import org.codehaus.plexus.redback.system.DefaultSecuritySession;
59 import org.codehaus.plexus.redback.system.SecuritySession;
60 import org.codehaus.plexus.redback.system.SecuritySystem;
61 import org.codehaus.plexus.redback.users.User;
62 import org.codehaus.plexus.redback.users.UserNotFoundException;
63 import org.codehaus.plexus.taskqueue.TaskQueueException;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.springframework.stereotype.Service;
68 import javax.inject.Inject;
69 import javax.inject.Named;
70 import javax.ws.rs.PathParam;
72 import java.io.FileInputStream;
73 import java.io.FileOutputStream;
74 import java.io.IOException;
75 import java.util.ArrayList;
76 import java.util.Calendar;
77 import java.util.Collections;
78 import java.util.Date;
79 import java.util.List;
82 * @author Olivier Lamy
85 @Service( "repositoriesService#rest" )
86 public class DefaultRepositoriesService
87 extends AbstractRestService
88 implements RepositoriesService
90 private Logger log = LoggerFactory.getLogger( getClass() );
93 @Named( value = "archivaTaskScheduler#repository" )
94 private RepositoryArchivaTaskScheduler repositoryTaskScheduler;
97 @Named( value = "taskExecutor#indexing" )
98 private ArchivaIndexingTaskExecutor archivaIndexingTaskExecutor;
101 private ManagedRepositoryAdmin managedRepositoryAdmin;
104 private PlexusSisuBridge plexusSisuBridge;
107 private MavenIndexerUtils mavenIndexerUtils;
110 private SecuritySystem securitySystem;
113 private RepositoryContentFactory repositoryFactory;
116 private ArchivaAdministration archivaAdministration;
119 @Named( value = "archivaTaskScheduler#repository" )
120 private ArchivaTaskScheduler scheduler;
122 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
124 public Boolean scanRepository( String repositoryId, boolean fullScan )
126 if ( repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId ) )
128 log.info( "scanning of repository with id {} already scheduled", repositoryId );
129 return Boolean.FALSE;
131 RepositoryTask task = new RepositoryTask();
132 task.setRepositoryId( repositoryId );
133 task.setScanAll( fullScan );
136 repositoryTaskScheduler.queueTask( task );
138 catch ( TaskQueueException e )
140 log.error( "failed to schedule scanning of repo with id {}", repositoryId, e );
146 public Boolean alreadyScanning( String repositoryId )
148 return repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId );
151 public Boolean removeScanningTaskFromQueue( String repositoryId )
153 RepositoryTask task = new RepositoryTask();
154 task.setRepositoryId( repositoryId );
157 return repositoryTaskScheduler.unQueueTask( task );
159 catch ( TaskQueueException e )
161 log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
166 public Boolean scanRepositoryNow( String repositoryId, boolean fullScan )
167 throws ArchivaRestServiceException
172 ManagedRepository repository = managedRepositoryAdmin.getManagedRepository( repositoryId );
174 IndexingContext context =
175 ArtifactIndexingTask.createContext( repository, plexusSisuBridge.lookup( NexusIndexer.class ),
176 new ArrayList<IndexCreator>(
177 mavenIndexerUtils.getAllIndexCreators() ) );
178 ArtifactIndexingTask task =
179 new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, context );
181 task.setExecuteOnEntireRepo( true );
182 task.setOnlyUpdate( false );
184 archivaIndexingTaskExecutor.executeTask( task );
187 catch ( Exception e )
189 log.error( e.getMessage(), e );
190 throw new ArchivaRestServiceException( e.getMessage() );
194 public Boolean copyArtifact( ArtifactTransferRequest artifactTransferRequest )
195 throws ArchivaRestServiceException
198 String userName = getAuditInformation().getUser().getUsername();
199 if ( StringUtils.isBlank( userName ) )
201 throw new ArchivaRestServiceException( "copyArtifact call: userName not found" );
204 if ( StringUtils.isBlank( artifactTransferRequest.getRepositoryId() ) )
206 throw new ArchivaRestServiceException( "copyArtifact call: sourceRepositoryId cannot be null" );
209 if ( StringUtils.isBlank( artifactTransferRequest.getTargetRepositoryId() ) )
211 throw new ArchivaRestServiceException( "copyArtifact call: targetRepositoryId cannot be null" );
214 ManagedRepository source = null;
217 source = managedRepositoryAdmin.getManagedRepository( artifactTransferRequest.getRepositoryId() );
219 catch ( RepositoryAdminException e )
221 throw new ArchivaRestServiceException( e.getMessage() );
224 if ( source == null )
226 throw new ArchivaRestServiceException(
227 "cannot find repository with id " + artifactTransferRequest.getRepositoryId() );
230 ManagedRepository target = null;
233 target = managedRepositoryAdmin.getManagedRepository( artifactTransferRequest.getTargetRepositoryId() );
235 catch ( RepositoryAdminException e )
237 throw new ArchivaRestServiceException( e.getMessage() );
240 if ( target == null )
242 throw new ArchivaRestServiceException(
243 "cannot find repository with id " + artifactTransferRequest.getTargetRepositoryId() );
246 if ( StringUtils.isBlank( artifactTransferRequest.getGroupId() ) )
248 throw new ArchivaRestServiceException( "groupId is mandatory" );
251 if ( StringUtils.isBlank( artifactTransferRequest.getArtifactId() ) )
253 throw new ArchivaRestServiceException( "artifactId is mandatory" );
256 if ( StringUtils.isBlank( artifactTransferRequest.getVersion() ) )
258 throw new ArchivaRestServiceException( "version is mandatory" );
261 if ( VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
263 throw new ArchivaRestServiceException( "copy of SNAPSHOT not supported" );
266 // end check parameters
271 user = securitySystem.getUserManager().findUser( userName );
273 catch ( UserNotFoundException e )
275 throw new ArchivaRestServiceException( "user " + userName + " not found" );
278 // check karma on source : read
279 AuthenticationResult authn = new AuthenticationResult( true, userName, null );
280 SecuritySession securitySession = new DefaultSecuritySession( authn, user );
284 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
285 artifactTransferRequest.getRepositoryId() );
288 throw new ArchivaRestServiceException(
289 "not authorized to access repo:" + artifactTransferRequest.getRepositoryId() );
292 catch ( AuthorizationException e )
294 log.error( "error reading permission: " + e.getMessage(), e );
295 throw new ArchivaRestServiceException( e.getMessage() );
298 // check karma on target: write
302 securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
303 artifactTransferRequest.getTargetRepositoryId() );
306 throw new ArchivaRestServiceException(
307 "not authorized to write to repo:" + artifactTransferRequest.getTargetRepositoryId() );
310 catch ( AuthorizationException e )
312 log.error( "error reading permission: " + e.getMessage(), e );
313 throw new ArchivaRestServiceException( e.getMessage() );
316 // sounds good we can continue !
318 ArtifactReference artifactReference = new ArtifactReference();
319 artifactReference.setArtifactId( artifactTransferRequest.getArtifactId() );
320 artifactReference.setGroupId( artifactTransferRequest.getGroupId() );
321 artifactReference.setVersion( artifactTransferRequest.getVersion() );
322 artifactReference.setClassifier( artifactTransferRequest.getClassifier() );
323 String packaging = StringUtils.trim( artifactTransferRequest.getPackaging() );
324 artifactReference.setType( StringUtils.isEmpty( packaging ) ? "jar" : packaging );
329 ManagedRepositoryContent sourceRepository =
330 repositoryFactory.getManagedRepositoryContent( artifactTransferRequest.getRepositoryId() );
332 String artifactSourcePath = sourceRepository.toPath( artifactReference );
334 File artifactFile = new File( source.getLocation(), artifactSourcePath );
336 ManagedRepositoryContent targetRepository =
337 repositoryFactory.getManagedRepositoryContent( artifactTransferRequest.getTargetRepositoryId() );
339 String artifactPath = targetRepository.toPath( artifactReference );
341 int lastIndex = artifactPath.lastIndexOf( '/' );
343 String path = artifactPath.substring( 0, lastIndex );
344 File targetPath = new File( target.getLocation(), path );
346 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
347 int newBuildNumber = 1;
348 String timestamp = null;
350 File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
351 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
353 if ( !targetPath.exists() )
358 String filename = artifactPath.substring( lastIndex + 1 );
360 // FIXME some dupe with uploadaction
362 boolean fixChecksums =
363 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
365 File targetFile = new File( targetPath, filename );
366 if ( targetFile.exists() && target.isBlockRedeployments() )
368 throw new ArchivaRestServiceException(
369 "artifact already exists in target repo: " + artifactTransferRequest.getTargetRepositoryId()
370 + " and redeployment blocked" );
374 copyFile( artifactFile, targetPath, filename, fixChecksums );
375 queueRepositoryTask( target.getId(), targetFile );
378 // copy source pom to target repo
379 String pomFilename = filename;
380 if ( StringUtils.isNotBlank( artifactTransferRequest.getClassifier() ) )
382 pomFilename = StringUtils.remove( pomFilename, "-" + artifactTransferRequest.getClassifier() );
384 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
386 File pomFile = new File(
387 new File( source.getLocation(), artifactSourcePath.substring( 0, artifactPath.lastIndexOf( '/' ) ) ),
390 if ( pomFile != null && pomFile.length() > 0 )
392 copyFile( pomFile, targetPath, pomFilename, fixChecksums );
393 queueRepositoryTask( target.getId(), new File( targetPath, pomFilename ) );
398 // explicitly update only if metadata-updater consumer is not enabled!
399 if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
401 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
402 fixChecksums, artifactTransferRequest );
408 "Artifact \'" + artifactTransferRequest.getGroupId() + ":" + artifactTransferRequest.getArtifactId()
409 + ":" + artifactTransferRequest.getVersion() + "\' was successfully deployed to repository \'"
410 + artifactTransferRequest.getTargetRepositoryId() + "\'";
413 catch ( RepositoryException e )
415 log.error( "RepositoryException: " + e.getMessage(), e );
416 throw new ArchivaRestServiceException( e.getMessage() );
418 catch ( RepositoryAdminException e )
420 log.error( "RepositoryAdminException: " + e.getMessage(), e );
421 throw new ArchivaRestServiceException( e.getMessage() );
423 catch ( IOException e )
425 log.error( "IOException: " + e.getMessage(), e );
426 throw new ArchivaRestServiceException( e.getMessage() );
431 //FIXME some duplicate with UploadAction
433 private void queueRepositoryTask( String repositoryId, File localFile )
435 RepositoryTask task = new RepositoryTask();
436 task.setRepositoryId( repositoryId );
437 task.setResourceFile( localFile );
438 task.setUpdateRelatedArtifacts( true );
439 //task.setScanAll( true );
443 scheduler.queueTask( task );
445 catch ( TaskQueueException e )
447 log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
452 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
453 throws RepositoryMetadataException
455 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
456 if ( metadataFile.exists() )
458 metadata = RepositoryMetadataReader.read( metadataFile );
463 private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
466 FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
467 FileInputStream input = new FileInputStream( sourceFile );
471 IOUtils.copy( input, out );
481 fixChecksums( new File( targetPath, targetFilename ) );
485 private void fixChecksums( File file )
487 ChecksummedFile checksum = new ChecksummedFile( file );
488 checksum.fixChecksums( algorithms );
491 private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
492 boolean fixChecksums, ArtifactTransferRequest artifactTransferRequest )
493 throws RepositoryMetadataException
495 List<String> availableVersions = new ArrayList<String>();
496 String latestVersion = artifactTransferRequest.getVersion();
498 File projectDir = new File( targetPath ).getParentFile();
499 File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
501 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
503 if ( projectMetadataFile.exists() )
505 availableVersions = projectMetadata.getAvailableVersions();
507 Collections.sort( availableVersions, VersionComparator.getInstance() );
509 if ( !availableVersions.contains( artifactTransferRequest.getVersion() ) )
511 availableVersions.add( artifactTransferRequest.getVersion() );
514 latestVersion = availableVersions.get( availableVersions.size() - 1 );
518 availableVersions.add( artifactTransferRequest.getVersion() );
520 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
521 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
524 if ( projectMetadata.getGroupId() == null )
526 projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
529 if ( projectMetadata.getArtifactId() == null )
531 projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
534 projectMetadata.setLatestVersion( latestVersion );
535 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
536 projectMetadata.setAvailableVersions( availableVersions );
538 if ( !VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
540 projectMetadata.setReleasedVersion( latestVersion );
543 RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
547 fixChecksums( projectMetadataFile );