]> source.dussan.org Git - archiva.git/blob
ac92822244635fdcd58b9bdbd49a50a3552d95d5
[archiva.git] /
1 package org.apache.maven.archiva.web.action;
2
3 /*
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
22 import java.io.File;
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;
34
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.Auditable;
52 import org.apache.maven.archiva.repository.metadata.MetadataTools;
53 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
54 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
55 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
56 import org.apache.maven.archiva.repository.project.ProjectModelException;
57 import org.apache.maven.archiva.repository.project.ProjectModelWriter;
58 import org.apache.maven.archiva.repository.project.writers.ProjectModel400Writer;
59 import org.apache.maven.archiva.security.AccessDeniedException;
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
64 import com.opensymphony.xwork2.Preparable;
65 import com.opensymphony.xwork2.Validateable;
66 import org.apache.commons.io.FilenameUtils;
67 import org.apache.commons.lang.StringUtils;
68
69 /**
70  * Upload an artifact using Jakarta file upload in webwork. If set by the user a pom will also be generated. Metadata
71  * will also be updated if one exists, otherwise it would be created.
72  * 
73  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="uploadAction" instantiation-strategy="per-lookup"
74  */
75 public class UploadAction
76     extends PlexusActionSupport
77     implements Validateable, Preparable, Auditable
78 {
79     /**
80       * @plexus.requirement
81       */
82      private RepositoryContentConsumers consumers;
83      
84      /**
85      * The groupId of the artifact to be deployed.
86      */
87     private String groupId;
88
89     /**
90      * The artifactId of the artifact to be deployed.
91      */
92     private String artifactId;
93
94     /**
95      * The version of the artifact to be deployed.
96      */
97     private String version;
98
99     /**
100      * The packaging of the artifact to be deployed.
101      */
102     private String packaging;
103
104     /**
105      * The classifier of the artifact to be deployed.
106      */
107     private String classifier;
108
109     /**
110      * The temporary file representing the artifact to be deployed.
111      */
112     private File artifactFile;
113
114     /**
115      * The temporary file representing the pom to be deployed alongside the artifact.
116      */
117     private File pomFile;
118
119     /**
120      * The repository where the artifact is to be deployed.
121      */
122     private String repositoryId;
123
124     /**
125      * Flag whether to generate a pom for the artifact or not.
126      */
127     private boolean generatePom;
128
129     /**
130      * List of managed repositories to deploy to.
131      */
132     private List<String> managedRepoIdList;
133
134     /**
135      * @plexus.requirement
136      */
137     private UserRepositories userRepositories;
138
139     /**
140      * @plexus.requirement role-hint="default"
141      */
142     private ArchivaConfiguration configuration;
143
144     /**
145      * @plexus.requirement
146      */
147     private RepositoryContentFactory repositoryFactory;
148     
149     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
150
151     private ProjectModelWriter pomWriter = new ProjectModel400Writer();
152     
153     public void setArtifact( File file )
154     {
155         this.artifactFile = file;
156     }
157
158     public void setArtifactContentType( String contentType )
159     {
160         StringUtils.trim( contentType );
161     }
162
163     public void setArtifactFileName( String filename )
164     {
165         StringUtils.trim( filename );
166     }
167
168     public void setPom( File file )
169     {
170         this.pomFile = file;
171     }
172
173     public void setPomContentType( String contentType )
174     {
175         StringUtils.trim( contentType );
176     }
177
178     public void setPomFileName( String filename )
179     {
180         StringUtils.trim( filename );
181     }
182
183     public String getGroupId()
184     {
185         return groupId;
186     }
187
188     public void setGroupId( String groupId )
189     {
190         this.groupId = StringUtils.trim( groupId );
191     }
192
193     public String getArtifactId()
194     {
195         return artifactId;
196     }
197
198     public void setArtifactId( String artifactId )
199     {
200         this.artifactId = StringUtils.trim( artifactId );
201     }
202
203     public String getVersion()
204     {
205         return version;
206     }
207
208     public void setVersion( String version )
209     {
210         this.version = StringUtils.trim( version );
211     }
212
213     public String getPackaging()
214     {
215         return packaging;
216     }
217
218     public void setPackaging( String packaging )
219     {
220         this.packaging = StringUtils.trim( packaging );
221     }
222
223     public String getClassifier()
224     {
225         return classifier;
226     }
227
228     public void setClassifier( String classifier )
229     {
230         this.classifier = StringUtils.trim( classifier );
231     }
232
233     public String getRepositoryId()
234     {
235         return repositoryId;
236     }
237
238     public void setRepositoryId( String repositoryId )
239     {
240         this.repositoryId = repositoryId;
241     }
242
243     public boolean isGeneratePom()
244     {
245         return generatePom;
246     }
247
248     public void setGeneratePom( boolean generatePom )
249     {
250         this.generatePom = generatePom;
251     }
252
253     public List<String> getManagedRepoIdList()
254     {
255         return managedRepoIdList;
256     }
257
258     public void setManagedRepoIdList( List<String> managedRepoIdList )
259     {
260         this.managedRepoIdList = managedRepoIdList;
261     }
262
263     public void prepare()
264     {
265         managedRepoIdList = getManagableRepos();
266     }
267
268     public String input()
269     {
270         return INPUT;
271     }
272
273     private void reset()
274     {
275         // reset the fields so the form is clear when 
276         // the action returns to the jsp page
277         groupId = "";
278         artifactId = "";
279         version = "";
280         packaging = "";
281         classifier = "";
282         artifactFile = null;
283         pomFile = null;
284         repositoryId = "";
285         generatePom = false;
286     }
287     
288     public String doUpload()
289     {
290         try
291         {
292             ManagedRepositoryConfiguration repoConfig =
293                 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
294
295             ArtifactReference artifactReference = new ArtifactReference();
296             artifactReference.setArtifactId( artifactId );
297             artifactReference.setGroupId( groupId );
298             artifactReference.setVersion( version );
299             artifactReference.setClassifier( classifier );
300             artifactReference.setType( packaging );
301
302             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
303
304             String artifactPath = repository.toPath( artifactReference );
305
306             int lastIndex = artifactPath.lastIndexOf( '/' );
307
308             File targetPath = new File( repoConfig.getLocation(), artifactPath.substring( 0, lastIndex ) );
309
310             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
311             int newBuildNumber = -1;
312             String timestamp = null;
313             
314             File metadataFile = getMetadata( targetPath.getAbsolutePath() );
315             ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
316
317             if (VersionUtil.isSnapshot(version))
318             {
319                 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
320                 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
321                 fmt.setTimeZone( timezone );
322                 timestamp = fmt.format( lastUpdatedTimestamp );
323                 if ( metadata.getSnapshotVersion() != null )
324                 {
325                     newBuildNumber = metadata.getSnapshotVersion().getBuildNumber() + 1;
326                 }
327                 else
328                 {
329                         metadata.setSnapshotVersion( new SnapshotVersion() );
330                         newBuildNumber = 1;
331                 }
332             }
333
334             if ( !targetPath.exists() )
335             {
336                 targetPath.mkdirs();
337             }
338
339             String filename = artifactPath.substring( lastIndex + 1 );
340             if ( VersionUtil.isSnapshot( version ) )
341             {
342                 filename = filename.replaceAll( "SNAPSHOT", timestamp + "-" + newBuildNumber );
343             }
344
345             try
346             {
347                 copyFile( artifactFile, targetPath, filename );
348                 consumers.executeConsumers( repoConfig, repository.toFile( artifactReference ) );
349             }
350             catch ( IOException ie )
351             {
352                 addActionError( "Error encountered while uploading file: " + ie.getMessage() );
353                 return ERROR;
354             }
355
356             String pomFilename = filename;
357             if( classifier != null && !"".equals( classifier ) )
358             {
359                 pomFilename = StringUtils.remove( pomFilename, "-" + classifier );
360             }
361             pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
362                 
363             if ( generatePom )
364             {
365                 try
366                 {
367                     File generatedPomFile = createPom( targetPath, pomFilename );
368                     consumers.executeConsumers( repoConfig, generatedPomFile );
369                 }
370                 catch ( IOException ie )
371                 {
372                     addActionError( "Error encountered while writing pom file: " + ie.getMessage() );
373                     return ERROR;
374                 }
375                 catch ( ProjectModelException pe )
376                 {
377                     addActionError( "Error encountered while generating pom file: " + pe.getMessage() );
378                     return ERROR;
379                 }
380             }
381             
382             if ( pomFile != null && pomFile.length() > 0 ) 
383             {
384                 try
385                 {                    
386                     copyFile( pomFile, targetPath, pomFilename );
387                     consumers.executeConsumers( repoConfig, new File( targetPath, pomFilename ) );
388                 }
389                 catch ( IOException ie )
390                 {
391                     addActionError( "Error encountered while uploading pom file: " + ie.getMessage() );
392                     return ERROR;
393                 }
394                 
395             }
396
397             updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, timestamp, newBuildNumber );
398
399             String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version +
400                 "\' was successfully deployed to repository \'" + repositoryId + "\'";
401                         
402             triggerAuditEvent( repositoryId, groupId + ":" + artifactId + ":" + version, AuditEvent.UPLOAD_FILE );
403             
404             addActionMessage( msg );
405
406             reset();
407             return SUCCESS;
408         }
409         catch ( RepositoryNotFoundException re )
410         {
411             addActionError( "Target repository cannot be found: " + re.getMessage() );
412             return ERROR;
413         }
414         catch ( RepositoryException rep )
415         {
416             addActionError( "Repository exception: " + rep.getMessage() );
417             return ERROR;
418         }
419     }
420
421     private void copyFile( File sourceFile, File targetPath, String targetFilename )
422         throws IOException
423     {
424         FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
425
426         try
427         {
428             FileInputStream input = new FileInputStream( sourceFile );
429             int i = 0;
430             while ( ( i = input.read() ) != -1 )
431             {
432                 out.write( i );
433             }
434             out.flush();
435         }
436         finally
437         {
438             out.close();
439         }
440     }
441
442     private File createPom( File targetPath, String filename )
443         throws IOException, ProjectModelException
444     {
445         ArchivaProjectModel projectModel = new ArchivaProjectModel();
446         projectModel.setGroupId( groupId );
447         projectModel.setArtifactId( artifactId );
448         projectModel.setVersion( version );
449         projectModel.setPackaging( packaging );
450         
451         File pomFile = new File( targetPath, filename);        
452         pomWriter.write( projectModel, pomFile );
453
454         return pomFile;
455     }
456
457     private File getMetadata( String targetPath )
458     {
459         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
460
461         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
462     }
463
464     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
465         throws RepositoryMetadataException
466     {
467         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
468         if ( metadataFile.exists() )
469         {
470             metadata = RepositoryMetadataReader.read( metadataFile );
471         }
472         return metadata;
473     }
474
475     /**
476      * Update artifact level metadata. If it does not exist, create the metadata.
477      * 
478      * @param metadata
479      */
480     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp,
481                                  String timestamp, int buildNumber )
482         throws RepositoryMetadataException
483     {
484         List<String> availableVersions = new ArrayList<String>();
485         String latestVersion = version;
486
487         if ( metadataFile.exists() )
488         {
489             availableVersions = metadata.getAvailableVersions();
490
491             Collections.sort( availableVersions, VersionComparator.getInstance() );
492
493             if ( !availableVersions.contains( version ) )
494             {
495                 availableVersions.add( version );
496             }
497
498             latestVersion = availableVersions.get( availableVersions.size() - 1 );
499         }
500         else
501         {
502             availableVersions.add( version );
503
504             metadata.setGroupId( groupId );
505             metadata.setArtifactId( artifactId );
506         }
507
508         if ( metadata.getGroupId() == null )
509         {
510                 metadata.setGroupId( groupId );
511         }
512         if ( metadata.getArtifactId() == null )
513         {
514                 metadata.setArtifactId( artifactId );
515         }
516
517         metadata.setLatestVersion( latestVersion );
518         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
519         metadata.setAvailableVersions( availableVersions );
520
521         if ( !VersionUtil.isSnapshot( version ) )
522         {
523             metadata.setReleasedVersion( latestVersion );
524         }
525         else
526         {
527             metadata.getSnapshotVersion().setBuildNumber( buildNumber );
528
529             metadata.getSnapshotVersion().setTimestamp( timestamp );
530         }
531
532         RepositoryMetadataWriter.write( metadata, metadataFile );
533         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
534         checksum.fixChecksums( algorithms );
535     }
536
537     public void validate()
538     {
539         try
540         {
541             // is this enough check for the repository permission?
542             if ( !userRepositories.isAuthorizedToUploadArtifacts( getPrincipal(), repositoryId ) )
543             {
544                 addActionError( "User is not authorized to upload in repository " + repositoryId );
545             }
546
547             if ( artifactFile == null || artifactFile.length() == 0 )
548             {
549                 addActionError( "Please add a file to upload." );
550             }
551             
552             if ( !VersionUtil.isVersion( version ) )
553             {
554                 addActionError( "Invalid version." );
555             }            
556         }
557         catch ( PrincipalNotFoundException pe )
558         {
559             addActionError( pe.getMessage() );
560         }
561         catch ( ArchivaSecurityException ae )
562         {
563             addActionError( ae.getMessage() );
564         }
565     }
566     
567     private List<String> getManagableRepos()
568     {
569         try
570         {
571             return userRepositories.getManagableRepositoryIds( getPrincipal() );
572         }
573         catch ( PrincipalNotFoundException e )
574         {
575             log.warn( e.getMessage(), e );
576         }
577         catch ( AccessDeniedException e )
578         {
579             log.warn( e.getMessage(), e );
580             // TODO: pass this onto the screen.
581         }
582         catch ( ArchivaSecurityException e )
583         {
584             log.warn( e.getMessage(), e );
585         }
586         return Collections.emptyList();
587     }
588 }