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.Date;
31 import java.util.Collections;
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.maven.archiva.common.utils.VersionComparator;
38 import org.apache.maven.archiva.common.utils.VersionUtil;
39 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
40 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
41 import org.apache.maven.archiva.model.ArchivaProjectModel;
42 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
43 import org.apache.maven.archiva.model.ArtifactReference;
44 import org.apache.maven.archiva.model.SnapshotVersion;
45 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
46 import org.apache.maven.archiva.repository.RepositoryContentFactory;
47 import org.apache.maven.archiva.repository.RepositoryException;
48 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
49 import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
50 import org.apache.maven.archiva.repository.audit.AuditEvent;
51 import org.apache.maven.archiva.repository.audit.AuditListener;
52 import org.apache.maven.archiva.repository.audit.Auditable;
53 import org.apache.maven.archiva.repository.metadata.MetadataTools;
54 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
55 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
56 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
57 import org.apache.maven.archiva.repository.project.ProjectModelException;
58 import org.apache.maven.archiva.repository.project.ProjectModelWriter;
59 import org.apache.maven.archiva.repository.project.writers.ProjectModel400Writer;
60 import org.apache.maven.archiva.security.ArchivaSecurityException;
61 import org.apache.maven.archiva.security.PrincipalNotFoundException;
62 import org.apache.maven.archiva.security.UserRepositories;
63 import org.apache.maven.archiva.security.ArchivaXworkUser;
64 import org.codehaus.plexus.xwork.action.PlexusActionSupport;
66 import com.opensymphony.webwork.ServletActionContext;
67 import com.opensymphony.xwork.ActionContext;
68 import com.opensymphony.xwork.Preparable;
69 import com.opensymphony.xwork.Validateable;
70 import org.apache.commons.io.FilenameUtils;
73 * Upload an artifact using Jakarta file upload in webwork. If set by the user a pom will also be generated. Metadata
74 * will also be updated if one exists, otherwise it would be created.
76 * @author <a href="mailto:wsmoak@apache.org">Wendy Smoak</a>
77 * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
78 * @plexus.component role="com.opensymphony.xwork.Action" role-hint="uploadAction"
80 public class UploadAction
81 extends PlexusActionSupport
82 implements Validateable, Preparable, Auditable
87 private RepositoryContentConsumers consumers;
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 content type of the artifact to be deployed.
122 private String artifactContentType;
125 * The original filename of the uploaded artifact file.
127 private String artifactFilename;
130 * The temporary file representing the pom to be deployed alongside the artifact.
132 private File pomFile;
135 * The content type of the pom file.
137 private String pomContentType;
140 * The original filename of the uploaded pom file.
142 private String pomFilename;
145 * The repository where the artifact is to be deployed.
147 private String repositoryId;
150 * Flag whether to generate a pom for the artifact or not.
152 private boolean generatePom;
155 * List of managed repositories to deploy to.
157 private List<String> managedRepoIdList;
160 * @plexus.requirement
162 private UserRepositories userRepositories;
165 * @plexus.requirement role-hint="default"
167 private ArchivaConfiguration configuration;
170 * @plexus.requirement
172 private RepositoryContentFactory repositoryFactory;
175 * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
177 private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
179 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
181 private ProjectModelWriter pomWriter = new ProjectModel400Writer();
183 public void setArtifact( File file )
185 this.artifactFile = file;
188 public void setArtifactContentType( String contentType )
190 this.artifactContentType = contentType;
193 public void setArtifactFileName( String filename )
195 this.artifactFilename = filename;
198 public void setPom( File file )
203 public void setPomContentType( String contentType )
205 this.pomContentType = contentType;
208 public void setPomFileName( String filename )
210 this.pomFilename = filename;
213 public String getGroupId()
218 public void setGroupId( String groupId )
220 this.groupId = groupId;
223 public String getArtifactId()
228 public void setArtifactId( String artifactId )
230 this.artifactId = artifactId;
233 public String getVersion()
238 public void setVersion( String version )
240 this.version = version;
243 public String getPackaging()
248 public void setPackaging( String packaging )
250 this.packaging = packaging;
253 public String getClassifier()
258 public void setClassifier( String classifier )
260 this.classifier = classifier;
263 public String getRepositoryId()
268 public void setRepositoryId( String repositoryId )
270 this.repositoryId = repositoryId;
273 public boolean isGeneratePom()
278 public void setGeneratePom( boolean generatePom )
280 this.generatePom = generatePom;
283 public List<String> getManagedRepoIdList()
285 return managedRepoIdList;
288 public void setManagedRepoIdList( List<String> managedRepoIdList )
290 this.managedRepoIdList = managedRepoIdList;
293 public void prepare()
296 new ArrayList<String>( configuration.getConfiguration().getManagedRepositoriesAsMap().keySet() );
299 public String input()
306 // reset the fields so the form is clear when
307 // the action returns to the jsp page
314 artifactContentType = "";
315 artifactFilename = "";
323 public String doUpload()
327 ManagedRepositoryConfiguration repoConfig =
328 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
330 ArtifactReference artifactReference = new ArtifactReference();
331 artifactReference.setArtifactId( artifactId );
332 artifactReference.setGroupId( groupId );
333 artifactReference.setVersion( version );
334 artifactReference.setClassifier( classifier );
335 artifactReference.setType( packaging );
337 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
339 String artifactPath = repository.toPath( artifactReference );
341 int lastIndex = artifactPath.lastIndexOf( '/' );
343 File targetPath = new File( repoConfig.getLocation(), artifactPath.substring( 0, lastIndex ) );
345 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
346 int newBuildNumber = -1;
347 String timestamp = null;
349 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
350 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
352 if (VersionUtil.isSnapshot(version))
354 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
355 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
356 fmt.setTimeZone( timezone );
357 timestamp = fmt.format( lastUpdatedTimestamp );
358 if ( metadata.getSnapshotVersion() != null )
360 newBuildNumber = metadata.getSnapshotVersion().getBuildNumber() + 1;
364 metadata.setSnapshotVersion( new SnapshotVersion() );
369 if ( !targetPath.exists() )
374 String filename = artifactPath.substring( lastIndex + 1 );
375 if ( VersionUtil.isSnapshot( version ) )
377 filename = filename.replaceAll( "SNAPSHOT", timestamp + "-" + newBuildNumber );
382 copyFile( artifactFile, targetPath, filename );
383 consumers.executeConsumers( repoConfig, repository.toFile( artifactReference ) );
385 catch ( IOException ie )
387 addActionError( "Error encountered while uploading file: " + ie.getMessage() );
395 File generatedPomFile = createPom( targetPath, filename );
396 consumers.executeConsumers( repoConfig, generatedPomFile );
398 catch ( IOException ie )
400 addActionError( "Error encountered while writing pom file: " + ie.getMessage() );
403 catch ( ProjectModelException pe )
405 addActionError( "Error encountered while generating pom file: " + pe.getMessage() );
410 if ( pomFile != null && pomFile.length() > 0 )
414 String targetFilename = filename.replaceAll( packaging, "pom" );
415 copyFile( pomFile, targetPath, targetFilename );
416 consumers.executeConsumers( repoConfig, new File( targetPath, targetFilename ) );
418 catch ( IOException ie )
420 addActionError( "Error encountered while uploading pom file: " + ie.getMessage() );
426 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, timestamp, newBuildNumber );
428 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version +
429 "\' was successfully deployed to repository \'" + repositoryId + "\'";
431 triggerAuditEvent( getPrincipal(), repositoryId, groupId + ":" + artifactId + ":" + version, AuditEvent.UPLOAD_FILE );
433 addActionMessage( msg );
438 catch ( RepositoryNotFoundException re )
440 addActionError( "Target repository cannot be found: " + re.getMessage() );
443 catch ( RepositoryException rep )
445 addActionError( "Repository exception: " + rep.getMessage() );
450 private String getPrincipal()
452 return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
455 private void copyFile( File sourceFile, File targetPath, String targetFilename )
458 FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
462 FileInputStream input = new FileInputStream( sourceFile );
464 while ( ( i = input.read() ) != -1 )
476 private File createPom( File targetPath, String filename )
477 throws IOException, ProjectModelException
479 ArchivaProjectModel projectModel = new ArchivaProjectModel();
480 projectModel.setGroupId( groupId );
481 projectModel.setArtifactId( artifactId );
482 projectModel.setVersion( version );
483 projectModel.setPackaging( packaging );
485 filename = FilenameUtils.removeExtension(filename) + ".pom";
486 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.
516 private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp,
517 String timestamp, int buildNumber )
518 throws RepositoryMetadataException
520 List<String> availableVersions = new ArrayList<String>();
521 String latestVersion = version;
523 if ( metadataFile.exists() )
525 availableVersions = metadata.getAvailableVersions();
527 Collections.sort( availableVersions, VersionComparator.getInstance() );
529 if ( !availableVersions.contains( version ) )
531 availableVersions.add( version );
534 latestVersion = availableVersions.get( availableVersions.size() - 1 );
538 availableVersions.add( version );
540 metadata.setGroupId( groupId );
541 metadata.setArtifactId( artifactId );
544 if ( metadata.getGroupId() == null )
546 metadata.setGroupId( groupId );
548 if ( metadata.getArtifactId() == null )
550 metadata.setArtifactId( artifactId );
553 metadata.setLatestVersion( latestVersion );
554 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
555 metadata.setAvailableVersions( availableVersions );
557 if ( !VersionUtil.isSnapshot( version ) )
559 metadata.setReleasedVersion( latestVersion );
563 metadata.getSnapshotVersion().setBuildNumber( buildNumber );
565 metadata.getSnapshotVersion().setTimestamp( timestamp );
568 RepositoryMetadataWriter.write( metadata, metadataFile );
569 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
570 checksum.fixChecksums( algorithms );
573 public void validate()
577 // is this enough check for the repository permission?
578 if ( !userRepositories.isAuthorizedToUploadArtifacts( getPrincipal(), repositoryId ) )
580 addActionError( "User is not authorized to upload in repository " + repositoryId );
583 if ( artifactFile == null || artifactFile.length() == 0 )
585 addActionError( "Please add a file to upload." );
588 if ( !VersionUtil.isVersion( version ) )
590 addActionError( "Invalid version." );
593 catch ( PrincipalNotFoundException pe )
595 addActionError( pe.getMessage() );
597 catch ( ArchivaSecurityException ae )
599 addActionError( ae.getMessage() );
603 public void addAuditListener( AuditListener listener )
605 this.auditListeners.add( listener );
608 public void clearAuditListeners()
610 this.auditListeners.clear();
613 public void removeAuditListener( AuditListener listener )
615 this.auditListeners.remove( listener );
618 private void triggerAuditEvent( String user, String repositoryId, String resource, String action )
620 AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
621 event.setRemoteIP( ServletActionContext.getRequest().getRemoteAddr() );
623 for ( AuditListener listener : auditListeners )
625 listener.auditEvent( event );