]> source.dussan.org Git - archiva.git/blob
eefe81a7bad0b61565a63d7b34ac23ac813028d7
[archiva.git] /
1 package org.apache.archiva.web.api;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import com.google.common.base.Predicate;
22 import com.google.common.collect.Iterables;
23 import org.apache.archiva.admin.model.RepositoryAdminException;
24 import org.apache.archiva.admin.model.admin.ArchivaAdministration;
25 import org.apache.archiva.admin.model.beans.ManagedRepository;
26 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
27 import org.apache.archiva.audit.AuditEvent;
28 import org.apache.archiva.checksum.ChecksumAlgorithm;
29 import org.apache.archiva.checksum.ChecksummedFile;
30 import org.apache.archiva.common.utils.VersionComparator;
31 import org.apache.archiva.common.utils.VersionUtil;
32 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
33 import org.apache.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.archiva.model.ArtifactReference;
35 import org.apache.archiva.model.SnapshotVersion;
36 import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
37 import org.apache.archiva.repository.ManagedRepositoryContent;
38 import org.apache.archiva.repository.RepositoryContentFactory;
39 import org.apache.archiva.repository.RepositoryException;
40 import org.apache.archiva.repository.RepositoryNotFoundException;
41 import org.apache.archiva.repository.metadata.MetadataTools;
42 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
43 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
44 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
45 import org.apache.archiva.rest.services.AbstractRestService;
46 import org.apache.archiva.scheduler.ArchivaTaskScheduler;
47 import org.apache.archiva.scheduler.repository.model.RepositoryTask;
48 import org.apache.archiva.web.model.FileMetadata;
49 import org.apache.archiva.xml.XMLException;
50 import org.apache.commons.io.FilenameUtils;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang.BooleanUtils;
53 import org.apache.commons.lang.StringUtils;
54 import org.apache.commons.lang.SystemUtils;
55 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
56 import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
57 import org.apache.maven.model.Model;
58 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import org.springframework.stereotype.Service;
62
63
64 import javax.inject.Inject;
65 import javax.inject.Named;
66 import javax.servlet.http.HttpServletRequest;
67 import javax.ws.rs.core.Context;
68 import javax.ws.rs.core.Response;
69 import java.io.File;
70 import java.io.FileInputStream;
71 import java.io.FileOutputStream;
72 import java.io.FileWriter;
73 import java.io.IOException;
74 import java.text.DateFormat;
75 import java.text.SimpleDateFormat;
76 import java.util.ArrayList;
77 import java.util.Calendar;
78 import java.util.Collections;
79 import java.util.Date;
80 import java.util.Iterator;
81 import java.util.List;
82 import java.util.TimeZone;
83 import java.util.concurrent.CopyOnWriteArrayList;
84
85 /**
86  * @author Olivier Lamy
87  */
88 @Service("fileUploadService#rest")
89 public class DefaultFileUploadService
90     extends AbstractRestService
91     implements FileUploadService
92 {
93     private Logger log = LoggerFactory.getLogger( getClass() );
94
95     @Context
96     private HttpServletRequest httpServletRequest;
97
98     @Inject
99     private ManagedRepositoryAdmin managedRepositoryAdmin;
100
101     @Inject
102     private RepositoryContentFactory repositoryFactory;
103
104     @Inject
105     private ArchivaAdministration archivaAdministration;
106
107     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
108
109     @Inject
110     @Named(value = "archivaTaskScheduler#repository")
111     private ArchivaTaskScheduler scheduler;
112
113     private String getStringValue( MultipartBody multipartBody, String attachmentId )
114         throws IOException
115     {
116         Attachment attachment = multipartBody.getAttachment( attachmentId );
117         return attachment == null ? "" : IOUtils.toString( attachment.getDataHandler().getInputStream() );
118     }
119
120     public FileMetadata post( MultipartBody multipartBody )
121         throws ArchivaRestServiceException
122     {
123
124         try
125         {
126
127             String classifier = getStringValue( multipartBody, "classifier" );
128             String packaging = getStringValue( multipartBody, "packaging" );
129             // skygo: http header form pomFile was once sending 1 for true and void for false
130             // leading to permanent false value for pomFile if using toBoolean(); use , "1", ""
131             boolean pomFile = BooleanUtils.toBoolean( getStringValue( multipartBody, "pomFile" ) );
132
133             Attachment file = multipartBody.getAttachment( "files[]" );
134
135             //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar"
136             String fileName = file.getContentDisposition().getParameter( "filename" );
137
138             File tmpFile = File.createTempFile( "upload-artifact", ".tmp" );
139             tmpFile.deleteOnExit();
140             IOUtils.copy( file.getDataHandler().getInputStream(), new FileOutputStream( tmpFile ) );
141             FileMetadata fileMetadata = new FileMetadata( fileName, tmpFile.length(), "theurl" );
142             fileMetadata.setServerFileName( tmpFile.getPath() );
143             fileMetadata.setClassifier( classifier );
144             fileMetadata.setDeleteUrl( tmpFile.getName() );
145             fileMetadata.setPomFile( pomFile );
146             fileMetadata.setPackaging( packaging );
147
148             log.info( "uploading file: {}", fileMetadata );
149
150             List<FileMetadata> fileMetadatas = getSessionFilesList();
151
152             fileMetadatas.add( fileMetadata );
153
154             return fileMetadata;
155         }
156         catch ( IOException e )
157         {
158             throw new ArchivaRestServiceException( e.getMessage(),
159                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
160         }
161
162     }
163
164     /**
165      * FIXME must be per session synchronized not globally
166      *
167      * @return
168      */
169     protected synchronized List<FileMetadata> getSessionFilesList()
170     {
171         List<FileMetadata> fileMetadatas =
172             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
173         if ( fileMetadatas == null )
174         {
175             fileMetadatas = new CopyOnWriteArrayList<FileMetadata>();
176             httpServletRequest.getSession().setAttribute( FILES_SESSION_KEY, fileMetadatas );
177         }
178         return fileMetadatas;
179     }
180
181     public Boolean deleteFile( String fileName )
182         throws ArchivaRestServiceException
183     {
184         File file = new File( SystemUtils.getJavaIoTmpDir(), fileName );
185         log.debug( "delete file:{},exists:{}", file.getPath(), file.exists() );
186         boolean removed = getSessionFileMetadatas().remove( new FileMetadata( fileName ) );
187         // try with full name as ui only know the file name
188         if ( !removed )
189         {
190             removed = getSessionFileMetadatas().remove( new FileMetadata( file.getPath() ) );
191         }
192         if ( file.exists() )
193         {
194             return file.delete();
195         }
196         return Boolean.FALSE;
197     }
198
199     public Boolean clearUploadedFiles()
200         throws ArchivaRestServiceException
201     {
202         List<FileMetadata> fileMetadatas = new ArrayList( getSessionFileMetadatas() );
203         for ( FileMetadata fileMetadata : fileMetadatas )
204         {
205             deleteFile( new File( fileMetadata.getServerFileName() ).getPath() );
206         }
207         getSessionFileMetadatas().clear();
208         return Boolean.TRUE;
209     }
210
211     public List<FileMetadata> getSessionFileMetadatas()
212         throws ArchivaRestServiceException
213     {
214         List<FileMetadata> fileMetadatas =
215             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
216
217         return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas;
218     }
219
220     public Boolean save( String repositoryId, String groupId, String artifactId, String version, String packaging,
221                          boolean generatePom )
222         throws ArchivaRestServiceException
223     {
224         repositoryId = StringUtils.trim( repositoryId );
225         groupId = StringUtils.trim( groupId );
226         artifactId = StringUtils.trim( artifactId );
227         version = StringUtils.trim( version );
228         packaging = StringUtils.trim( packaging );
229
230         List<FileMetadata> fileMetadatas = getSessionFilesList();
231         if ( fileMetadatas == null || fileMetadatas.isEmpty() )
232         {
233             return Boolean.FALSE;
234         }
235
236         try
237         {
238             ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repositoryId );
239
240             if ( managedRepository == null )
241             {
242                 // TODO i18n ?
243                 throw new ArchivaRestServiceException( "Cannot find managed repository with id " + repositoryId,
244                                                        Response.Status.BAD_REQUEST.getStatusCode(), null );
245             }
246
247             if ( VersionUtil.isSnapshot( version ) && !managedRepository.isSnapshots() )
248             {
249                 // TODO i18n ?
250                 throw new ArchivaRestServiceException(
251                     "Managed repository with id " + repositoryId + " do not accept snapshots",
252                     Response.Status.BAD_REQUEST.getStatusCode(), null );
253             }
254         }
255         catch ( RepositoryAdminException e )
256         {
257             throw new ArchivaRestServiceException( e.getMessage(),
258                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
259         }
260
261         // get from the session file with groupId/artifactId
262
263         Iterable<FileMetadata> filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
264         {
265             public boolean apply( FileMetadata fileMetadata )
266             {
267                 return fileMetadata != null && !fileMetadata.isPomFile();
268             }
269         } );
270         Iterator<FileMetadata> iterator = filesToAdd.iterator();
271         boolean pomGenerated = false;
272         while ( iterator.hasNext() )
273         {
274             FileMetadata fileMetadata = iterator.next();
275             log.debug( "fileToAdd: {}", fileMetadata );
276             saveFile( repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
277                       packaging );
278             pomGenerated = true;
279             deleteFile( fileMetadata.getServerFileName() );
280         }
281
282         filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
283         {
284             public boolean apply( FileMetadata fileMetadata )
285             {
286                 return fileMetadata != null && fileMetadata.isPomFile();
287             }
288         } );
289
290         iterator = filesToAdd.iterator();
291         while ( iterator.hasNext() )
292         {
293             FileMetadata fileMetadata = iterator.next();
294             log.debug( "fileToAdd: {}", fileMetadata );
295             savePomFile( repositoryId, fileMetadata, groupId, artifactId, version, packaging );
296             deleteFile( fileMetadata.getServerFileName() );
297         }
298
299         return Boolean.TRUE;
300     }
301
302     protected void savePomFile( String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
303                                 String version, String packaging )
304         throws ArchivaRestServiceException
305     {
306
307         try
308         {
309             boolean fixChecksums =
310                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
311
312             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
313
314             ArtifactReference artifactReference = new ArtifactReference();
315             artifactReference.setArtifactId( artifactId );
316             artifactReference.setGroupId( groupId );
317             artifactReference.setVersion( version );
318             artifactReference.setClassifier( fileMetadata.getClassifier() );
319             artifactReference.setType( packaging );
320
321             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
322
323             String artifactPath = repository.toPath( artifactReference );
324
325             int lastIndex = artifactPath.lastIndexOf( '/' );
326
327             String path = artifactPath.substring( 0, lastIndex );
328             File targetPath = new File( repoConfig.getLocation(), path );
329
330             String pomFilename = artifactPath.substring( lastIndex + 1 );
331             if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
332             {
333                 pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
334             }
335             pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
336
337             copyFile( new File( fileMetadata.getServerFileName() ), targetPath, pomFilename, fixChecksums );
338             triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
339             queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
340         }
341         catch ( IOException ie )
342         {
343             throw new ArchivaRestServiceException( "Error encountered while uploading pom file: " + ie.getMessage(),
344                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
345         }
346         catch ( RepositoryException rep )
347         {
348             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
349                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
350         }
351         catch ( RepositoryAdminException e )
352         {
353             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
354                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
355         }
356     }
357
358     protected void saveFile( String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
359                              String artifactId, String version, String packaging )
360         throws ArchivaRestServiceException
361     {
362         try
363         {
364
365             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
366
367             ArtifactReference artifactReference = new ArtifactReference();
368             artifactReference.setArtifactId( artifactId );
369             artifactReference.setGroupId( groupId );
370             artifactReference.setVersion( version );
371             artifactReference.setClassifier( fileMetadata.getClassifier() );
372             artifactReference.setType(
373                 StringUtils.isEmpty( fileMetadata.getPackaging() ) ? packaging : fileMetadata.getPackaging() );
374
375             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
376
377             String artifactPath = repository.toPath( artifactReference );
378
379             int lastIndex = artifactPath.lastIndexOf( '/' );
380
381             String path = artifactPath.substring( 0, lastIndex );
382             File targetPath = new File( repoConfig.getLocation(), path );
383
384             log.debug( "artifactPath: {} found targetPath: {}", artifactPath, targetPath );
385
386             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
387             int newBuildNumber = -1;
388             String timestamp = null;
389
390             File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
391             ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
392
393             if ( VersionUtil.isSnapshot( version ) )
394             {
395                 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
396                 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
397                 fmt.setTimeZone( timezone );
398                 timestamp = fmt.format( lastUpdatedTimestamp );
399                 if ( versionMetadata.getSnapshotVersion() != null )
400                 {
401                     newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
402                 }
403                 else
404                 {
405                     newBuildNumber = 1;
406                 }
407             }
408
409             if ( !targetPath.exists() )
410             {
411                 targetPath.mkdirs();
412             }
413
414             String filename = artifactPath.substring( lastIndex + 1 );
415             if ( VersionUtil.isSnapshot( version ) )
416             {
417                 filename = filename.replaceAll( VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber );
418             }
419
420             boolean fixChecksums =
421                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
422
423             try
424             {
425                 File targetFile = new File( targetPath, filename );
426                 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
427                 {
428                     throw new ArchivaRestServiceException(
429                         "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
430                         Response.Status.BAD_REQUEST.getStatusCode(), null );
431                 }
432                 else
433                 {
434                     copyFile( new File( fileMetadata.getServerFileName() ), targetPath, filename, fixChecksums );
435                     triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
436                     queueRepositoryTask( repository.getId(), targetFile );
437                 }
438             }
439             catch ( IOException ie )
440             {
441                 log.error( "IOException copying file: {}", ie.getMessage(), ie );
442                 throw new ArchivaRestServiceException(
443                     "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
444                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
445             }
446
447             if ( generatePom )
448             {
449                 String pomFilename = filename;
450                 if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
451                 {
452                     pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
453                 }
454                 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
455
456                 try
457                 {
458                     File generatedPomFile =
459                         createPom( targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging );
460                     triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
461                     if ( fixChecksums )
462                     {
463                         fixChecksums( generatedPomFile );
464                     }
465                     queueRepositoryTask( repoConfig.getId(), generatedPomFile );
466                 }
467                 catch ( IOException ie )
468                 {
469                     throw new ArchivaRestServiceException(
470                         "Error encountered while writing pom file: " + ie.getMessage(),
471                         Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
472                 }
473             }
474
475             // explicitly update only if metadata-updater consumer is not enabled!
476             if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
477             {
478                 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
479                                        fixChecksums, fileMetadata, groupId, artifactId, version, packaging );
480
481                 if ( VersionUtil.isSnapshot( version ) )
482                 {
483                     updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
484                                            newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
485                                            packaging );
486                 }
487             }
488         }
489         catch ( RepositoryNotFoundException re )
490         {
491             throw new ArchivaRestServiceException( "Target repository cannot be found: " + re.getMessage(),
492                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re );
493         }
494         catch ( RepositoryException rep )
495         {
496             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
497                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
498         }
499         catch ( RepositoryAdminException e )
500         {
501             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
502                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
503         }
504     }
505
506     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
507         throws RepositoryMetadataException
508     {
509         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
510         if ( metadataFile.exists() )
511         {
512             try
513             {
514                 metadata = MavenMetadataReader.read( metadataFile );
515             }
516             catch ( XMLException e )
517             {
518                 throw new RepositoryMetadataException( e.getMessage(), e );
519             }
520         }
521         return metadata;
522     }
523
524     private File createPom( File targetPath, String filename, FileMetadata fileMetadata, String groupId,
525                             String artifactId, String version, String packaging )
526         throws IOException
527     {
528         Model projectModel = new Model();
529         projectModel.setModelVersion( "4.0.0" );
530         projectModel.setGroupId( groupId );
531         projectModel.setArtifactId( artifactId );
532         projectModel.setVersion( version );
533         projectModel.setPackaging( packaging );
534
535         File pomFile = new File( targetPath, filename );
536         MavenXpp3Writer writer = new MavenXpp3Writer();
537         FileWriter w = new FileWriter( pomFile );
538         try
539         {
540             writer.write( w, projectModel );
541         }
542         finally
543         {
544             IOUtils.closeQuietly( w );
545         }
546
547         return pomFile;
548     }
549
550     private void fixChecksums( File file )
551     {
552         ChecksummedFile checksum = new ChecksummedFile( file );
553         checksum.fixChecksums( algorithms );
554     }
555
556     private void queueRepositoryTask( String repositoryId, File localFile )
557     {
558         RepositoryTask task = new RepositoryTask();
559         task.setRepositoryId( repositoryId );
560         task.setResourceFile( localFile );
561         task.setUpdateRelatedArtifacts( true );
562         task.setScanAll( false );
563
564         try
565         {
566             scheduler.queueTask( task );
567         }
568         catch ( TaskQueueException e )
569         {
570             log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
571                            + "']." );
572         }
573     }
574
575     private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
576         throws IOException
577     {
578         FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
579         FileInputStream input = new FileInputStream( sourceFile );
580
581         try
582         {
583             IOUtils.copy( input, out );
584         }
585         finally
586         {
587             out.close();
588             input.close();
589         }
590
591         if ( fixChecksums )
592         {
593             fixChecksums( new File( targetPath, targetFilename ) );
594         }
595     }
596
597     /**
598      * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
599      */
600     private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
601                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
602                                         String artifactId, String version, String packaging )
603         throws RepositoryMetadataException
604     {
605         List<String> availableVersions = new ArrayList<String>();
606         String latestVersion = version;
607
608         File projectDir = new File( targetPath ).getParentFile();
609         File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
610
611         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
612
613         if ( projectMetadataFile.exists() )
614         {
615             availableVersions = projectMetadata.getAvailableVersions();
616
617             Collections.sort( availableVersions, VersionComparator.getInstance() );
618
619             if ( !availableVersions.contains( version ) )
620             {
621                 availableVersions.add( version );
622             }
623
624             latestVersion = availableVersions.get( availableVersions.size() - 1 );
625         }
626         else
627         {
628             availableVersions.add( version );
629
630             projectMetadata.setGroupId( groupId );
631             projectMetadata.setArtifactId( artifactId );
632         }
633
634         if ( projectMetadata.getGroupId() == null )
635         {
636             projectMetadata.setGroupId( groupId );
637         }
638
639         if ( projectMetadata.getArtifactId() == null )
640         {
641             projectMetadata.setArtifactId( artifactId );
642         }
643
644         projectMetadata.setLatestVersion( latestVersion );
645         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
646         projectMetadata.setAvailableVersions( availableVersions );
647
648         if ( !VersionUtil.isSnapshot( version ) )
649         {
650             projectMetadata.setReleasedVersion( latestVersion );
651         }
652
653         RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
654
655         if ( fixChecksums )
656         {
657             fixChecksums( projectMetadataFile );
658         }
659     }
660
661     /**
662      * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
663      * if necessary.
664      */
665     private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
666                                         Date lastUpdatedTimestamp, String timestamp, int buildNumber,
667                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
668                                         String artifactId, String version, String packaging )
669         throws RepositoryMetadataException
670     {
671         if ( !metadataFile.exists() )
672         {
673             metadata.setGroupId( groupId );
674             metadata.setArtifactId( artifactId );
675             metadata.setVersion( version );
676         }
677
678         if ( metadata.getSnapshotVersion() == null )
679         {
680             metadata.setSnapshotVersion( new SnapshotVersion() );
681         }
682
683         metadata.getSnapshotVersion().setBuildNumber( buildNumber );
684         metadata.getSnapshotVersion().setTimestamp( timestamp );
685         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
686
687         RepositoryMetadataWriter.write( metadata, metadataFile );
688
689         if ( fixChecksums )
690         {
691             fixChecksums( metadataFile );
692         }
693     }
694
695
696 }