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
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.text.DateFormat;
27 import java.text.SimpleDateFormat;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.Collections;
31 import java.util.Date;
32 import java.util.List;
33 import java.util.TimeZone;
35 import org.apache.archiva.checksum.ChecksumAlgorithm;
36 import org.apache.archiva.checksum.ChecksummedFile;
37 import org.apache.commons.io.FilenameUtils;
38 import org.apache.commons.lang.StringUtils;
39 import org.apache.maven.archiva.common.utils.VersionComparator;
40 import org.apache.maven.archiva.common.utils.VersionUtil;
41 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
42 import org.apache.maven.archiva.configuration.Configuration;
43 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
44 import org.apache.maven.archiva.model.ArchivaProjectModel;
45 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
46 import org.apache.maven.archiva.model.ArtifactReference;
47 import org.apache.maven.archiva.model.SnapshotVersion;
48 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
49 import org.apache.maven.archiva.repository.RepositoryContentFactory;
50 import org.apache.maven.archiva.repository.RepositoryException;
51 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
52 import org.apache.maven.archiva.repository.audit.AuditEvent;
53 import org.apache.maven.archiva.repository.audit.Auditable;
54 import org.apache.maven.archiva.repository.metadata.MetadataTools;
55 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
56 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
57 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
58 import org.apache.maven.archiva.repository.project.ProjectModelException;
59 import org.apache.maven.archiva.repository.project.ProjectModelWriter;
60 import org.apache.maven.archiva.repository.project.writers.ProjectModel400Writer;
61 import org.apache.maven.archiva.scheduled.ArchivaTaskScheduler;
62 import org.apache.maven.archiva.scheduled.tasks.RepositoryTask;
63 import org.apache.maven.archiva.scheduled.tasks.TaskCreator;
64 import org.apache.maven.archiva.security.AccessDeniedException;
65 import org.apache.maven.archiva.security.ArchivaSecurityException;
66 import org.apache.maven.archiva.security.PrincipalNotFoundException;
67 import org.apache.maven.archiva.security.UserRepositories;
68 import org.codehaus.plexus.taskqueue.TaskQueueException;
70 import com.opensymphony.xwork2.Preparable;
71 import com.opensymphony.xwork2.Validateable;
74 * Upload an artifact using Jakarta file upload in webwork. If set by the user a pom will also be generated. Metadata
75 * will also be updated if one exists, otherwise it would be created.
77 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="uploadAction" instantiation-strategy="per-lookup"
79 public class UploadAction
80 extends PlexusActionSupport
81 implements Validateable, Preparable, Auditable
84 * The groupId of the artifact to be deployed.
86 private String groupId;
89 * The artifactId of the artifact to be deployed.
91 private String artifactId;
94 * The version of the artifact to be deployed.
96 private String version;
99 * The packaging of the artifact to be deployed.
101 private String packaging;
104 * The classifier of the artifact to be deployed.
106 private String classifier;
109 * The temporary file representing the artifact to be deployed.
111 private File artifactFile;
114 * The temporary file representing the pom to be deployed alongside the artifact.
116 private File pomFile;
119 * The repository where the artifact is to be deployed.
121 private String repositoryId;
124 * Flag whether to generate a pom for the artifact or not.
126 private boolean generatePom;
129 * List of managed repositories to deploy to.
131 private List<String> managedRepoIdList;
134 * @plexus.requirement
136 private UserRepositories userRepositories;
139 * @plexus.requirement role-hint="default"
141 private ArchivaConfiguration configuration;
144 * @plexus.requirement
146 private RepositoryContentFactory repositoryFactory;
149 * @plexus.requirement
151 private ArchivaTaskScheduler scheduler;
153 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5};
155 private ProjectModelWriter pomWriter = new ProjectModel400Writer();
157 public void setArtifact( File file )
159 this.artifactFile = file;
162 public void setArtifactContentType( String contentType )
164 StringUtils.trim( contentType );
167 public void setArtifactFileName( String filename )
169 StringUtils.trim( filename );
172 public void setPom( File file )
177 public void setPomContentType( String contentType )
179 StringUtils.trim( contentType );
182 public void setPomFileName( String filename )
184 StringUtils.trim( filename );
187 public String getGroupId()
192 public void setGroupId( String groupId )
194 this.groupId = StringUtils.trim( groupId );
197 public String getArtifactId()
202 public void setArtifactId( String artifactId )
204 this.artifactId = StringUtils.trim( artifactId );
207 public String getVersion()
212 public void setVersion( String version )
214 this.version = StringUtils.trim( version );
217 public String getPackaging()
222 public void setPackaging( String packaging )
224 this.packaging = StringUtils.trim( packaging );
227 public String getClassifier()
232 public void setClassifier( String classifier )
234 this.classifier = StringUtils.trim( classifier );
237 public String getRepositoryId()
242 public void setRepositoryId( String repositoryId )
244 this.repositoryId = repositoryId;
247 public boolean isGeneratePom()
252 public void setGeneratePom( boolean generatePom )
254 this.generatePom = generatePom;
257 public List<String> getManagedRepoIdList()
259 return managedRepoIdList;
262 public void setManagedRepoIdList( List<String> managedRepoIdList )
264 this.managedRepoIdList = managedRepoIdList;
267 public void prepare()
269 managedRepoIdList = getManagableRepos();
272 public String input()
279 // reset the fields so the form is clear when
280 // the action returns to the jsp page
292 public String doUpload()
296 Configuration config = configuration.getConfiguration();
297 ManagedRepositoryConfiguration repoConfig =
298 config.findManagedRepositoryById( repositoryId );
300 ArtifactReference artifactReference = new ArtifactReference();
301 artifactReference.setArtifactId( artifactId );
302 artifactReference.setGroupId( groupId );
303 artifactReference.setVersion( version );
304 artifactReference.setClassifier( classifier );
305 artifactReference.setType( packaging );
307 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
309 String artifactPath = repository.toPath( artifactReference );
311 int lastIndex = artifactPath.lastIndexOf( '/' );
313 File targetPath = new File( repoConfig.getLocation(), artifactPath.substring( 0, lastIndex ) );
315 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
316 int newBuildNumber = -1;
317 String timestamp = null;
319 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
320 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
322 if ( VersionUtil.isSnapshot( version ) )
324 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
325 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
326 fmt.setTimeZone( timezone );
327 timestamp = fmt.format( lastUpdatedTimestamp );
328 if ( metadata.getSnapshotVersion() != null )
330 newBuildNumber = metadata.getSnapshotVersion().getBuildNumber() + 1;
334 metadata.setSnapshotVersion( new SnapshotVersion() );
339 if ( !targetPath.exists() )
344 String filename = artifactPath.substring( lastIndex + 1 );
345 if ( VersionUtil.isSnapshot( version ) )
347 filename = filename.replaceAll( "SNAPSHOT", timestamp + "-" + newBuildNumber );
350 boolean fixChecksums = !( config.getRepositoryScanning().getKnownContentConsumers().contains( "create-missing-checksums" ) );
354 File targetFile = new File( targetPath, filename );
355 if( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
357 addActionError( "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed." );
362 copyFile( artifactFile, targetPath, filename, fixChecksums );
363 queueRepositoryTask( repository.getId(), repository.toFile( artifactReference ) );
366 catch ( IOException ie )
368 addActionError( "Error encountered while uploading file: " + ie.getMessage() );
372 String pomFilename = filename;
373 if ( classifier != null && !"".equals( classifier ) )
375 pomFilename = StringUtils.remove( pomFilename, "-" + classifier );
377 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
383 File generatedPomFile = createPom( targetPath, pomFilename );
386 fixChecksums( generatedPomFile );
388 queueRepositoryTask( repoConfig.getId(), generatedPomFile );
390 catch ( IOException ie )
392 addActionError( "Error encountered while writing pom file: " + ie.getMessage() );
395 catch ( ProjectModelException pe )
397 addActionError( "Error encountered while generating pom file: " + pe.getMessage() );
402 if ( pomFile != null && pomFile.length() > 0 )
406 copyFile( pomFile, targetPath, pomFilename, fixChecksums );
407 queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
409 catch ( IOException ie )
411 addActionError( "Error encountered while uploading pom file: " + ie.getMessage() );
417 // explicitly update only if metadata-updater consumer is not enabled!
418 if( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
420 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, timestamp, newBuildNumber, fixChecksums );
423 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version +
424 "\' was successfully deployed to repository \'" + repositoryId + "\'";
426 triggerAuditEvent( repositoryId, artifactPath, AuditEvent.UPLOAD_FILE );
428 addActionMessage( msg );
433 catch ( RepositoryNotFoundException re )
435 addActionError( "Target repository cannot be found: " + re.getMessage() );
438 catch ( RepositoryException rep )
440 addActionError( "Repository exception: " + rep.getMessage() );
445 private void fixChecksums( File file )
447 ChecksummedFile checksum = new ChecksummedFile( file );
448 checksum.fixChecksums( algorithms );
451 private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
454 FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
455 FileInputStream input = new FileInputStream( sourceFile );
460 while ( ( i = input.read() ) != -1 )
474 fixChecksums( new File( targetPath, targetFilename ) );
478 private File createPom( File targetPath, String filename )
479 throws IOException, ProjectModelException
481 ArchivaProjectModel projectModel = new ArchivaProjectModel();
482 projectModel.setGroupId( groupId );
483 projectModel.setArtifactId( artifactId );
484 projectModel.setVersion( version );
485 projectModel.setPackaging( packaging );
487 File pomFile = new File( targetPath, filename );
488 pomWriter.write( projectModel, pomFile );
493 private File getMetadata( String targetPath )
495 String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
497 return new File( artifactPath, MetadataTools.MAVEN_METADATA );
500 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
501 throws RepositoryMetadataException
503 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
504 if ( metadataFile.exists() )
506 metadata = RepositoryMetadataReader.read( metadataFile );
512 * Update artifact level metadata. If it does not exist, create the metadata and
513 * fix checksums if necessary.
515 private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp,
516 String timestamp, int buildNumber, boolean fixChecksums )
517 throws RepositoryMetadataException
519 List<String> availableVersions = new ArrayList<String>();
520 String latestVersion = version;
522 if ( metadataFile.exists() )
524 availableVersions = metadata.getAvailableVersions();
526 Collections.sort( availableVersions, VersionComparator.getInstance() );
528 if ( !availableVersions.contains( version ) )
530 availableVersions.add( version );
533 latestVersion = availableVersions.get( availableVersions.size() - 1 );
537 availableVersions.add( version );
539 metadata.setGroupId( groupId );
540 metadata.setArtifactId( artifactId );
543 if ( metadata.getGroupId() == null )
545 metadata.setGroupId( groupId );
547 if ( metadata.getArtifactId() == null )
549 metadata.setArtifactId( artifactId );
552 metadata.setLatestVersion( latestVersion );
553 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
554 metadata.setAvailableVersions( availableVersions );
556 if ( !VersionUtil.isSnapshot( version ) )
558 metadata.setReleasedVersion( latestVersion );
562 metadata.getSnapshotVersion().setBuildNumber( buildNumber );
564 metadata.getSnapshotVersion().setTimestamp( timestamp );
567 RepositoryMetadataWriter.write( metadata, metadataFile );
571 fixChecksums( metadataFile );
575 public void validate()
579 // is this enough check for the repository permission?
580 if ( !userRepositories.isAuthorizedToUploadArtifacts( getPrincipal(), repositoryId ) )
582 addActionError( "User is not authorized to upload in repository " + repositoryId );
585 if ( artifactFile == null || artifactFile.length() == 0 )
587 addActionError( "Please add a file to upload." );
590 if ( version == null || !VersionUtil.isVersion( version ) )
592 addActionError( "Invalid version." );
595 catch ( PrincipalNotFoundException pe )
597 addActionError( pe.getMessage() );
599 catch ( ArchivaSecurityException ae )
601 addActionError( ae.getMessage() );
605 private List<String> getManagableRepos()
609 return userRepositories.getManagableRepositoryIds( getPrincipal() );
611 catch ( PrincipalNotFoundException e )
613 log.warn( e.getMessage(), e );
615 catch ( AccessDeniedException e )
617 log.warn( e.getMessage(), e );
618 // TODO: pass this onto the screen.
620 catch ( ArchivaSecurityException e )
622 log.warn( e.getMessage(), e );
624 return Collections.emptyList();
627 private void queueRepositoryTask( String repositoryId, File localFile )
629 RepositoryTask task = TaskCreator.createRepositoryTask( repositoryId, localFile, true, true );
633 scheduler.queueRepositoryTask( task );
635 catch ( TaskQueueException e )
638 "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName() +
643 public void setScheduler( ArchivaTaskScheduler scheduler )
645 this.scheduler = scheduler;
648 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
650 this.repositoryFactory = repositoryFactory;
653 public void setConfiguration( ArchivaConfiguration configuration )
655 this.configuration = configuration;