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 @SuppressWarnings( "serial" )
81 @Controller( "uploadAction" )
83 public class UploadAction
84 extends AbstractActionSupport
85 implements Validateable, Preparable, Auditable
88 * The groupId of the artifact to be deployed.
90 private String groupId;
93 * The artifactId of the artifact to be deployed.
95 private String artifactId;
98 * The version of the artifact to be deployed.
100 private String version;
103 * The packaging of the artifact to be deployed.
105 private String packaging;
108 * The classifier of the artifact to be deployed.
110 private String classifier;
113 * The temporary file representing the artifact to be deployed.
115 private File artifactFile;
118 * The temporary file representing the pom to be deployed alongside the artifact.
120 private File pomFile;
123 * The repository where the artifact is to be deployed.
125 private String repositoryId;
128 * Flag whether to generate a pom for the artifact or not.
130 private boolean generatePom;
133 * List of managed repositories to deploy to.
135 private List<String> managedRepoIdList;
138 private UserRepositories userRepositories;
141 private ArchivaConfiguration configuration;
144 private RepositoryContentFactory repositoryFactory;
147 @Named( value = "archivaTaskScheduler#repository" )
148 private ArchivaTaskScheduler scheduler;
150 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
152 public void setArtifact( File file )
154 this.artifactFile = file;
157 public void setArtifactContentType( String contentType )
159 StringUtils.trim( contentType );
162 public void setArtifactFileName( String filename )
164 StringUtils.trim( filename );
167 public void setPom( File file )
172 public void setPomContentType( String contentType )
174 StringUtils.trim( contentType );
177 public void setPomFileName( String filename )
179 StringUtils.trim( filename );
182 public String getGroupId()
187 public void setGroupId( String groupId )
189 this.groupId = StringUtils.trim( groupId );
192 public String getArtifactId()
197 public void setArtifactId( String artifactId )
199 this.artifactId = StringUtils.trim( artifactId );
202 public String getVersion()
207 public void setVersion( String version )
209 this.version = StringUtils.trim( version );
212 public String getPackaging()
217 public void setPackaging( String packaging )
219 this.packaging = StringUtils.trim( packaging );
222 public String getClassifier()
227 public void setClassifier( String classifier )
229 this.classifier = StringUtils.trim( classifier );
232 public String getRepositoryId()
237 public void setRepositoryId( String repositoryId )
239 this.repositoryId = repositoryId;
242 public boolean isGeneratePom()
247 public void setGeneratePom( boolean generatePom )
249 this.generatePom = generatePom;
252 public List<String> getManagedRepoIdList()
254 return managedRepoIdList;
257 public void setManagedRepoIdList( List<String> managedRepoIdList )
259 this.managedRepoIdList = managedRepoIdList;
262 public void prepare()
264 managedRepoIdList = getManagableRepos();
267 public String input()
274 // reset the fields so the form is clear when
275 // the action returns to the jsp page
287 public String doUpload()
291 Configuration config = configuration.getConfiguration();
292 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repositoryId );
294 ArtifactReference artifactReference = new ArtifactReference();
295 artifactReference.setArtifactId( artifactId );
296 artifactReference.setGroupId( groupId );
297 artifactReference.setVersion( version );
298 artifactReference.setClassifier( classifier );
299 artifactReference.setType( packaging );
301 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
303 String artifactPath = repository.toPath( artifactReference );
305 int lastIndex = artifactPath.lastIndexOf( '/' );
307 String path = artifactPath.substring( 0, lastIndex );
308 File targetPath = new File( repoConfig.getLocation(), path );
310 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
311 int newBuildNumber = -1;
312 String timestamp = null;
314 File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
315 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
317 if ( VersionUtil.isSnapshot( version ) )
319 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
320 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
321 fmt.setTimeZone( timezone );
322 timestamp = fmt.format( lastUpdatedTimestamp );
323 if ( versionMetadata.getSnapshotVersion() != null )
325 newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
333 if ( !targetPath.exists() )
338 String filename = artifactPath.substring( lastIndex + 1 );
339 if ( VersionUtil.isSnapshot( version ) )
341 filename = filename.replaceAll( "SNAPSHOT", timestamp + "-" + newBuildNumber );
344 boolean fixChecksums =
345 !( config.getRepositoryScanning().getKnownContentConsumers().contains( "create-missing-checksums" ) );
349 File targetFile = new File( targetPath, filename );
350 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
353 "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed." );
358 copyFile( artifactFile, targetPath, filename, fixChecksums );
359 triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
360 queueRepositoryTask( repository.getId(), targetFile );
363 catch ( IOException ie )
365 addActionError( "Error encountered while uploading file: " + ie.getMessage() );
369 String pomFilename = filename;
370 if ( classifier != null && !"".equals( classifier ) )
372 pomFilename = StringUtils.remove( pomFilename, "-" + classifier );
374 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
380 File generatedPomFile = createPom( targetPath, pomFilename );
381 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
384 fixChecksums( generatedPomFile );
386 queueRepositoryTask( repoConfig.getId(), generatedPomFile );
388 catch ( IOException ie )
390 addActionError( "Error encountered while writing pom file: " + ie.getMessage() );
395 if ( pomFile != null && pomFile.length() > 0 )
399 copyFile( pomFile, targetPath, pomFilename, fixChecksums );
400 triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
401 queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
403 catch ( IOException ie )
405 addActionError( "Error encountered while uploading pom file: " + ie.getMessage() );
411 // explicitly update only if metadata-updater consumer is not enabled!
412 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
414 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
417 if ( VersionUtil.isSnapshot( version ) )
419 updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
420 newBuildNumber, fixChecksums );
424 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version
425 + "\' was successfully deployed to repository \'" + repositoryId + "\'";
427 addActionMessage( msg );
432 catch ( RepositoryNotFoundException re )
434 addActionError( "Target repository cannot be found: " + re.getMessage() );
437 catch ( RepositoryException rep )
439 addActionError( "Repository exception: " + rep.getMessage() );
444 private void fixChecksums( File file )
446 ChecksummedFile checksum = new ChecksummedFile( file );
447 checksum.fixChecksums( algorithms );
450 private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
453 FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
454 FileInputStream input = new FileInputStream( sourceFile );
458 IOUtils.copy( input, out );
468 fixChecksums( new File( targetPath, targetFilename ) );
472 private File createPom( File targetPath, String filename )
475 Model projectModel = new Model();
476 projectModel.setModelVersion( "4.0.0" );
477 projectModel.setGroupId( groupId );
478 projectModel.setArtifactId( artifactId );
479 projectModel.setVersion( version );
480 projectModel.setPackaging( packaging );
482 File pomFile = new File( targetPath, filename );
483 MavenXpp3Writer writer = new MavenXpp3Writer();
484 FileWriter w = new FileWriter( pomFile );
487 writer.write( w, projectModel );
497 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
498 throws RepositoryMetadataException
500 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
501 if ( metadataFile.exists() )
503 metadata = RepositoryMetadataReader.read( metadataFile );
510 * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
513 private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
514 Date lastUpdatedTimestamp, String timestamp, int buildNumber,
515 boolean fixChecksums )
516 throws RepositoryMetadataException
518 if ( !metadataFile.exists() )
520 metadata.setGroupId( groupId );
521 metadata.setArtifactId( artifactId );
522 metadata.setVersion( version );
525 if ( metadata.getSnapshotVersion() == null )
527 metadata.setSnapshotVersion( new SnapshotVersion() );
530 metadata.getSnapshotVersion().setBuildNumber( buildNumber );
531 metadata.getSnapshotVersion().setTimestamp( timestamp );
532 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
534 RepositoryMetadataWriter.write( metadata, metadataFile );
538 fixChecksums( metadataFile );
543 * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
545 private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
546 boolean fixChecksums )
547 throws RepositoryMetadataException
549 List<String> availableVersions = new ArrayList<String>();
550 String latestVersion = version;
552 File projectDir = new File( targetPath ).getParentFile();
553 File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
555 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
557 if ( projectMetadataFile.exists() )
559 availableVersions = projectMetadata.getAvailableVersions();
561 Collections.sort( availableVersions, VersionComparator.getInstance() );
563 if ( !availableVersions.contains( version ) )
565 availableVersions.add( version );
568 latestVersion = availableVersions.get( availableVersions.size() - 1 );
572 availableVersions.add( version );
574 projectMetadata.setGroupId( groupId );
575 projectMetadata.setArtifactId( artifactId );
578 if ( projectMetadata.getGroupId() == null )
580 projectMetadata.setGroupId( groupId );
583 if ( projectMetadata.getArtifactId() == null )
585 projectMetadata.setArtifactId( artifactId );
588 projectMetadata.setLatestVersion( latestVersion );
589 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
590 projectMetadata.setAvailableVersions( availableVersions );
592 if ( !VersionUtil.isSnapshot( version ) )
594 projectMetadata.setReleasedVersion( latestVersion );
597 RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
601 fixChecksums( projectMetadataFile );
605 public void validate()
609 // is this enough check for the repository permission?
610 if ( !userRepositories.isAuthorizedToUploadArtifacts( getPrincipal(), repositoryId ) )
612 addActionError( "User is not authorized to upload in repository " + repositoryId );
615 if ( artifactFile == null || artifactFile.length() == 0 )
617 addActionError( "Please add a file to upload." );
620 if ( version == null || !VersionUtil.isVersion( version ) )
622 addActionError( "Invalid version." );
625 catch ( PrincipalNotFoundException pe )
627 addActionError( pe.getMessage() );
629 catch ( ArchivaSecurityException ae )
631 addActionError( ae.getMessage() );
635 private List<String> getManagableRepos()
639 return userRepositories.getManagableRepositoryIds( getPrincipal() );
641 catch ( PrincipalNotFoundException e )
643 log.warn( e.getMessage(), e );
645 catch ( AccessDeniedException e )
647 log.warn( e.getMessage(), e );
648 // TODO: pass this onto the screen.
650 catch ( ArchivaSecurityException e )
652 log.warn( e.getMessage(), e );
654 return Collections.emptyList();
657 private void queueRepositoryTask( String repositoryId, File localFile )
659 RepositoryTask task = new RepositoryTask();
660 task.setRepositoryId( repositoryId );
661 task.setResourceFile( localFile );
662 task.setUpdateRelatedArtifacts( true );
663 task.setScanAll( true );
667 scheduler.queueTask( task );
669 catch ( TaskQueueException e )
671 log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
676 public void setScheduler( ArchivaTaskScheduler scheduler )
678 this.scheduler = scheduler;
681 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
683 this.repositoryFactory = repositoryFactory;
686 public void setConfiguration( ArchivaConfiguration configuration )
688 this.configuration = configuration;