1 package org.apache.maven.archiva.web.action;
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 com.opensymphony.xwork2.Preparable;
23 import com.opensymphony.xwork2.Validateable;
24 import org.apache.archiva.audit.AuditEvent;
25 import org.apache.archiva.audit.Auditable;
26 import org.apache.archiva.checksum.ChecksumAlgorithm;
27 import org.apache.archiva.checksum.ChecksummedFile;
28 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
29 import org.apache.archiva.scheduler.repository.RepositoryTask;
30 import org.apache.commons.io.FilenameUtils;
31 import org.apache.commons.io.IOUtils;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.maven.archiva.common.utils.VersionComparator;
34 import org.apache.maven.archiva.common.utils.VersionUtil;
35 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
36 import org.apache.maven.archiva.configuration.Configuration;
37 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
38 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
39 import org.apache.maven.archiva.model.ArtifactReference;
40 import org.apache.maven.archiva.model.SnapshotVersion;
41 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
42 import org.apache.maven.archiva.repository.RepositoryContentFactory;
43 import org.apache.maven.archiva.repository.RepositoryException;
44 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
45 import org.apache.maven.archiva.repository.metadata.MetadataTools;
46 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
47 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
48 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
49 import org.apache.archiva.security.AccessDeniedException;
50 import org.apache.archiva.security.ArchivaSecurityException;
51 import org.apache.archiva.security.PrincipalNotFoundException;
52 import org.apache.archiva.security.UserRepositories;
53 import org.apache.maven.model.Model;
54 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
55 import org.codehaus.plexus.taskqueue.TaskQueueException;
56 import org.codehaus.plexus.util.IOUtil;
57 import org.springframework.context.annotation.Scope;
58 import org.springframework.stereotype.Controller;
60 import javax.inject.Inject;
61 import javax.inject.Named;
63 import java.io.FileInputStream;
64 import java.io.FileOutputStream;
65 import java.io.FileWriter;
66 import java.io.IOException;
67 import java.text.DateFormat;
68 import java.text.SimpleDateFormat;
69 import java.util.ArrayList;
70 import java.util.Calendar;
71 import java.util.Collections;
72 import java.util.Date;
73 import java.util.List;
74 import java.util.TimeZone;
77 * Upload an artifact using Jakarta file upload in webwork. If set by the user a pom will also be generated. Metadata
78 * will also be updated if one exists, otherwise it would be created.
80 * plexus.component role="com.opensymphony.xwork2.Action" role-hint="uploadAction" instantiation-strategy="per-lookup"
82 @SuppressWarnings( "serial" )
83 @Controller( "uploadAction" )
85 public class UploadAction
86 extends AbstractActionSupport
87 implements Validateable, Preparable, Auditable
90 * The groupId of the artifact to be deployed.
92 private String groupId;
95 * The artifactId of the artifact to be deployed.
97 private String artifactId;
100 * The version of the artifact to be deployed.
102 private String version;
105 * The packaging of the artifact to be deployed.
107 private String packaging;
110 * The classifier of the artifact to be deployed.
112 private String classifier;
115 * The temporary file representing the artifact to be deployed.
117 private File artifactFile;
120 * The temporary file representing the pom to be deployed alongside the artifact.
122 private File pomFile;
125 * The repository where the artifact is to be deployed.
127 private String repositoryId;
130 * Flag whether to generate a pom for the artifact or not.
132 private boolean generatePom;
135 * List of managed repositories to deploy to.
137 private List<String> managedRepoIdList;
143 private UserRepositories userRepositories;
146 * plexus.requirement role-hint="default"
149 private ArchivaConfiguration configuration;
155 private RepositoryContentFactory repositoryFactory;
158 * lexus.requirement role="org.apache.archiva.scheduler.ArchivaTaskScheduler" role-hint="repository"
161 @Named( value = "archivaTaskScheduler#repository" )
162 private ArchivaTaskScheduler scheduler;
164 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
166 public void setArtifact( File file )
168 this.artifactFile = file;
171 public void setArtifactContentType( String contentType )
173 StringUtils.trim( contentType );
176 public void setArtifactFileName( String filename )
178 StringUtils.trim( filename );
181 public void setPom( File file )
186 public void setPomContentType( String contentType )
188 StringUtils.trim( contentType );
191 public void setPomFileName( String filename )
193 StringUtils.trim( filename );
196 public String getGroupId()
201 public void setGroupId( String groupId )
203 this.groupId = StringUtils.trim( groupId );
206 public String getArtifactId()
211 public void setArtifactId( String artifactId )
213 this.artifactId = StringUtils.trim( artifactId );
216 public String getVersion()
221 public void setVersion( String version )
223 this.version = StringUtils.trim( version );
226 public String getPackaging()
231 public void setPackaging( String packaging )
233 this.packaging = StringUtils.trim( packaging );
236 public String getClassifier()
241 public void setClassifier( String classifier )
243 this.classifier = StringUtils.trim( classifier );
246 public String getRepositoryId()
251 public void setRepositoryId( String repositoryId )
253 this.repositoryId = repositoryId;
256 public boolean isGeneratePom()
261 public void setGeneratePom( boolean generatePom )
263 this.generatePom = generatePom;
266 public List<String> getManagedRepoIdList()
268 return managedRepoIdList;
271 public void setManagedRepoIdList( List<String> managedRepoIdList )
273 this.managedRepoIdList = managedRepoIdList;
276 public void prepare()
278 managedRepoIdList = getManagableRepos();
281 public String input()
288 // reset the fields so the form is clear when
289 // the action returns to the jsp page
301 public String doUpload()
305 Configuration config = configuration.getConfiguration();
306 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repositoryId );
308 ArtifactReference artifactReference = new ArtifactReference();
309 artifactReference.setArtifactId( artifactId );
310 artifactReference.setGroupId( groupId );
311 artifactReference.setVersion( version );
312 artifactReference.setClassifier( classifier );
313 artifactReference.setType( packaging );
315 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
317 String artifactPath = repository.toPath( artifactReference );
319 int lastIndex = artifactPath.lastIndexOf( '/' );
321 String path = artifactPath.substring( 0, lastIndex );
322 File targetPath = new File( repoConfig.getLocation(), path );
324 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
325 int newBuildNumber = -1;
326 String timestamp = null;
328 File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
329 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
331 if ( VersionUtil.isSnapshot( version ) )
333 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
334 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
335 fmt.setTimeZone( timezone );
336 timestamp = fmt.format( lastUpdatedTimestamp );
337 if ( versionMetadata.getSnapshotVersion() != null )
339 newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
347 if ( !targetPath.exists() )
352 String filename = artifactPath.substring( lastIndex + 1 );
353 if ( VersionUtil.isSnapshot( version ) )
355 filename = filename.replaceAll( "SNAPSHOT", timestamp + "-" + newBuildNumber );
358 boolean fixChecksums =
359 !( config.getRepositoryScanning().getKnownContentConsumers().contains( "create-missing-checksums" ) );
363 File targetFile = new File( targetPath, filename );
364 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
367 "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed." );
372 copyFile( artifactFile, targetPath, filename, fixChecksums );
373 triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
374 queueRepositoryTask( repository.getId(), targetFile );
377 catch ( IOException ie )
379 addActionError( "Error encountered while uploading file: " + ie.getMessage() );
383 String pomFilename = filename;
384 if ( classifier != null && !"".equals( classifier ) )
386 pomFilename = StringUtils.remove( pomFilename, "-" + classifier );
388 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
394 File generatedPomFile = createPom( targetPath, pomFilename );
395 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
398 fixChecksums( generatedPomFile );
400 queueRepositoryTask( repoConfig.getId(), generatedPomFile );
402 catch ( IOException ie )
404 addActionError( "Error encountered while writing pom file: " + ie.getMessage() );
409 if ( pomFile != null && pomFile.length() > 0 )
413 copyFile( pomFile, targetPath, pomFilename, fixChecksums );
414 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
415 queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
417 catch ( IOException ie )
419 addActionError( "Error encountered while uploading pom file: " + ie.getMessage() );
425 // explicitly update only if metadata-updater consumer is not enabled!
426 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
428 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
431 if ( VersionUtil.isSnapshot( version ) )
433 updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
434 newBuildNumber, fixChecksums );
438 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version
439 + "\' was successfully deployed to repository \'" + repositoryId + "\'";
441 addActionMessage( msg );
446 catch ( RepositoryNotFoundException re )
448 addActionError( "Target repository cannot be found: " + re.getMessage() );
451 catch ( RepositoryException rep )
453 addActionError( "Repository exception: " + rep.getMessage() );
458 private void fixChecksums( File file )
460 ChecksummedFile checksum = new ChecksummedFile( file );
461 checksum.fixChecksums( algorithms );
464 private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
467 FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
468 FileInputStream input = new FileInputStream( sourceFile );
472 IOUtils.copy( input, out );
482 fixChecksums( new File( targetPath, targetFilename ) );
486 private File createPom( File targetPath, String filename )
489 Model projectModel = new Model();
490 projectModel.setModelVersion( "4.0.0" );
491 projectModel.setGroupId( groupId );
492 projectModel.setArtifactId( artifactId );
493 projectModel.setVersion( version );
494 projectModel.setPackaging( packaging );
496 File pomFile = new File( targetPath, filename );
497 MavenXpp3Writer writer = new MavenXpp3Writer();
498 FileWriter w = new FileWriter( pomFile );
501 writer.write( w, projectModel );
511 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
512 throws RepositoryMetadataException
514 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
515 if ( metadataFile.exists() )
517 metadata = RepositoryMetadataReader.read( metadataFile );
524 * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
527 private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
528 Date lastUpdatedTimestamp, String timestamp, int buildNumber,
529 boolean fixChecksums )
530 throws RepositoryMetadataException
532 if ( !metadataFile.exists() )
534 metadata.setGroupId( groupId );
535 metadata.setArtifactId( artifactId );
536 metadata.setVersion( version );
539 if ( metadata.getSnapshotVersion() == null )
541 metadata.setSnapshotVersion( new SnapshotVersion() );
544 metadata.getSnapshotVersion().setBuildNumber( buildNumber );
545 metadata.getSnapshotVersion().setTimestamp( timestamp );
546 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
548 RepositoryMetadataWriter.write( metadata, metadataFile );
552 fixChecksums( metadataFile );
557 * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
559 private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
560 boolean fixChecksums )
561 throws RepositoryMetadataException
563 List<String> availableVersions = new ArrayList<String>();
564 String latestVersion = version;
566 File projectDir = new File( targetPath ).getParentFile();
567 File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
569 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
571 if ( projectMetadataFile.exists() )
573 availableVersions = projectMetadata.getAvailableVersions();
575 Collections.sort( availableVersions, VersionComparator.getInstance() );
577 if ( !availableVersions.contains( version ) )
579 availableVersions.add( version );
582 latestVersion = availableVersions.get( availableVersions.size() - 1 );
586 availableVersions.add( version );
588 projectMetadata.setGroupId( groupId );
589 projectMetadata.setArtifactId( artifactId );
592 if ( projectMetadata.getGroupId() == null )
594 projectMetadata.setGroupId( groupId );
597 if ( projectMetadata.getArtifactId() == null )
599 projectMetadata.setArtifactId( artifactId );
602 projectMetadata.setLatestVersion( latestVersion );
603 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
604 projectMetadata.setAvailableVersions( availableVersions );
606 if ( !VersionUtil.isSnapshot( version ) )
608 projectMetadata.setReleasedVersion( latestVersion );
611 RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
615 fixChecksums( projectMetadataFile );
619 public void validate()
623 // is this enough check for the repository permission?
624 if ( !userRepositories.isAuthorizedToUploadArtifacts( getPrincipal(), repositoryId ) )
626 addActionError( "User is not authorized to upload in repository " + repositoryId );
629 if ( artifactFile == null || artifactFile.length() == 0 )
631 addActionError( "Please add a file to upload." );
634 if ( version == null || !VersionUtil.isVersion( version ) )
636 addActionError( "Invalid version." );
639 catch ( PrincipalNotFoundException pe )
641 addActionError( pe.getMessage() );
643 catch ( ArchivaSecurityException ae )
645 addActionError( ae.getMessage() );
649 private List<String> getManagableRepos()
653 return userRepositories.getManagableRepositoryIds( getPrincipal() );
655 catch ( PrincipalNotFoundException e )
657 log.warn( e.getMessage(), e );
659 catch ( AccessDeniedException e )
661 log.warn( e.getMessage(), e );
662 // TODO: pass this onto the screen.
664 catch ( ArchivaSecurityException e )
666 log.warn( e.getMessage(), e );
668 return Collections.emptyList();
671 private void queueRepositoryTask( String repositoryId, File localFile )
673 RepositoryTask task = new RepositoryTask();
674 task.setRepositoryId( repositoryId );
675 task.setResourceFile( localFile );
676 task.setUpdateRelatedArtifacts( true );
677 task.setScanAll( true );
681 scheduler.queueTask( task );
683 catch ( TaskQueueException e )
685 log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
690 public void setScheduler( ArchivaTaskScheduler scheduler )
692 this.scheduler = scheduler;
695 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
697 this.repositoryFactory = repositoryFactory;
700 public void setConfiguration( ArchivaConfiguration configuration )
702 this.configuration = configuration;