]> source.dussan.org Git - archiva.git/blob
77b1c0c060435f309445f8a7762dba2c49f96aa4
[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             // skygo: http header form pomFile was once sending 1 for true and void for false
129             // leading to permanent false value for pomFile if using toBoolean(); use , "1", ""
130             boolean pomFile = BooleanUtils.toBoolean( getStringValue( multipartBody, "pomFile" ) );
131
132             Attachment file = multipartBody.getAttachment( "files[]" );
133
134             //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar"
135             String fileName = file.getContentDisposition().getParameter( "filename" );
136
137             File tmpFile = File.createTempFile( "upload-artifact", ".tmp" );
138             tmpFile.deleteOnExit();
139             IOUtils.copy( file.getDataHandler().getInputStream(), new FileOutputStream( tmpFile ) );
140             FileMetadata fileMetadata = new FileMetadata( fileName, tmpFile.length(), "theurl" );
141             fileMetadata.setServerFileName( tmpFile.getPath() );
142             fileMetadata.setClassifier( classifier );
143             fileMetadata.setDeleteUrl( tmpFile.getName() );
144             fileMetadata.setPomFile( pomFile );
145
146             log.info( "uploading file: {}", fileMetadata );
147
148             List<FileMetadata> fileMetadatas = getSessionFilesList();
149
150             fileMetadatas.add( fileMetadata );
151
152             return fileMetadata;
153         }
154         catch ( IOException e )
155         {
156             throw new ArchivaRestServiceException( e.getMessage(),
157                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
158         }
159
160     }
161
162     /**
163      * FIXME must be per session synchronized not globally
164      *
165      * @return
166      */
167     protected synchronized List<FileMetadata> getSessionFilesList()
168     {
169         List<FileMetadata> fileMetadatas =
170             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
171         if ( fileMetadatas == null )
172         {
173             fileMetadatas = new CopyOnWriteArrayList<FileMetadata>();
174             httpServletRequest.getSession().setAttribute( FILES_SESSION_KEY, fileMetadatas );
175         }
176         return fileMetadatas;
177     }
178
179     public Boolean deleteFile( String fileName )
180         throws ArchivaRestServiceException
181     {
182         File file = new File( SystemUtils.getJavaIoTmpDir(), fileName );
183         log.debug( "delete file:{},exists:{}", file.getPath(), file.exists() );
184         boolean removed = getSessionFileMetadatas().remove(
185             new FileMetadata( SystemUtils.getJavaIoTmpDir().getPath() + "/" + fileName ) );
186         if ( file.exists() )
187         {
188             return file.delete();
189         }
190         return Boolean.FALSE;
191     }
192
193     public Boolean clearUploadedFiles()
194         throws ArchivaRestServiceException
195     {
196         List<FileMetadata> fileMetadatas = new ArrayList( getSessionFileMetadatas() );
197         for ( FileMetadata fileMetadata : fileMetadatas )
198         {
199             deleteFile( new File( fileMetadata.getServerFileName() ).getName() );
200         }
201         return Boolean.TRUE;
202     }
203
204     public List<FileMetadata> getSessionFileMetadatas()
205         throws ArchivaRestServiceException
206     {
207         List<FileMetadata> fileMetadatas =
208             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
209
210         return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas;
211     }
212
213     public Boolean save( String repositoryId, String groupId, String artifactId, String version,
214                          String packaging, boolean generatePom )
215         throws ArchivaRestServiceException
216     {
217         repositoryId = StringUtils.trim( repositoryId );
218         groupId = StringUtils.trim( groupId );
219         artifactId = StringUtils.trim( artifactId );
220         version = StringUtils.trim( version );
221         packaging = StringUtils.trim( packaging );
222
223         List<FileMetadata> fileMetadatas = getSessionFilesList();
224         if ( fileMetadatas == null || fileMetadatas.isEmpty() )
225         {
226             return Boolean.FALSE;
227         }
228
229         try
230         {
231             ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repositoryId );
232
233             if ( managedRepository == null )
234             {
235                 // TODO i18n ?
236                 throw new ArchivaRestServiceException( "Cannot find managed repository with id " + repositoryId,
237                                                        Response.Status.BAD_REQUEST.getStatusCode(), null );
238             }
239
240             if ( VersionUtil.isSnapshot( version ) && !managedRepository.isSnapshots() )
241             {
242                 // TODO i18n ?
243                 throw new ArchivaRestServiceException(
244                     "Managed repository with id " + repositoryId + " do not accept snapshots",
245                     Response.Status.BAD_REQUEST.getStatusCode(), null );
246             }
247         }
248         catch ( RepositoryAdminException e )
249         {
250             throw new ArchivaRestServiceException( e.getMessage(),
251                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
252         }
253
254         // get from the session file with groupId/artifactId
255
256         Iterable<FileMetadata> filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
257         {
258             public boolean apply( FileMetadata fileMetadata )
259             {
260                 return fileMetadata != null && !fileMetadata.isPomFile();
261             }
262         } );
263         Iterator<FileMetadata> iterator = filesToAdd.iterator();
264         boolean pomGenerated = false;
265         while ( iterator.hasNext() )
266         {
267             FileMetadata fileMetadata = iterator.next();
268             log.debug( "fileToAdd: {}", fileMetadata );
269             saveFile( repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
270                       packaging );
271             pomGenerated = true;
272             deleteFile( fileMetadata.getServerFileName() );
273         }
274
275         filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
276         {
277             public boolean apply( FileMetadata fileMetadata )
278             {
279                 return fileMetadata != null && fileMetadata.isPomFile();
280             }
281         } );
282
283         iterator = filesToAdd.iterator();
284         while ( iterator.hasNext() )
285         {
286             FileMetadata fileMetadata = iterator.next();
287             log.debug( "fileToAdd: {}", fileMetadata );
288             savePomFile( repositoryId, fileMetadata, groupId, artifactId, version, packaging );
289             deleteFile( fileMetadata.getServerFileName() );
290         }
291
292         return Boolean.TRUE;
293     }
294
295     protected void savePomFile( String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
296                                 String version, String packaging )
297         throws ArchivaRestServiceException
298     {
299
300         try
301         {
302             boolean fixChecksums =
303                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
304
305             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
306
307             ArtifactReference artifactReference = new ArtifactReference();
308             artifactReference.setArtifactId( artifactId );
309             artifactReference.setGroupId( groupId );
310             artifactReference.setVersion( version );
311             artifactReference.setClassifier( fileMetadata.getClassifier() );
312             artifactReference.setType( packaging );
313
314             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
315
316             String artifactPath = repository.toPath( artifactReference );
317
318             int lastIndex = artifactPath.lastIndexOf( '/' );
319
320             String path = artifactPath.substring( 0, lastIndex );
321             File targetPath = new File( repoConfig.getLocation(), path );
322
323             String pomFilename = artifactPath.substring( lastIndex + 1 );
324             if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
325             {
326                 pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
327             }
328             pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
329
330             copyFile( new File( fileMetadata.getServerFileName() ), targetPath, pomFilename, fixChecksums );
331             triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
332             queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
333         }
334         catch ( IOException ie )
335         {
336             throw new ArchivaRestServiceException( "Error encountered while uploading pom file: " + ie.getMessage(),
337                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
338         }
339         catch ( RepositoryException rep )
340         {
341             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
342                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
343         }
344         catch ( RepositoryAdminException e )
345         {
346             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
347                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
348         }
349     }
350
351     protected void saveFile( String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
352                              String artifactId, String version, String packaging )
353         throws ArchivaRestServiceException
354     {
355         try
356         {
357
358             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
359
360             ArtifactReference artifactReference = new ArtifactReference();
361             artifactReference.setArtifactId( artifactId );
362             artifactReference.setGroupId( groupId );
363             artifactReference.setVersion( version );
364             artifactReference.setClassifier( fileMetadata.getClassifier() );
365             artifactReference.setType( packaging );
366
367             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
368
369             String artifactPath = repository.toPath( artifactReference );
370
371             int lastIndex = artifactPath.lastIndexOf( '/' );
372
373             String path = artifactPath.substring( 0, lastIndex );
374             File targetPath = new File( repoConfig.getLocation(), path );
375
376             log.debug( "artifactPath: {} found targetPath: {}", artifactPath, targetPath );
377
378             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
379             int newBuildNumber = -1;
380             String timestamp = null;
381
382             File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
383             ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
384
385             if ( VersionUtil.isSnapshot( version ) )
386             {
387                 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
388                 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
389                 fmt.setTimeZone( timezone );
390                 timestamp = fmt.format( lastUpdatedTimestamp );
391                 if ( versionMetadata.getSnapshotVersion() != null )
392                 {
393                     newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
394                 }
395                 else
396                 {
397                     newBuildNumber = 1;
398                 }
399             }
400
401             if ( !targetPath.exists() )
402             {
403                 targetPath.mkdirs();
404             }
405
406             String filename = artifactPath.substring( lastIndex + 1 );
407             if ( VersionUtil.isSnapshot( version ) )
408             {
409                 filename = filename.replaceAll( VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber );
410             }
411
412             boolean fixChecksums =
413                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
414
415             try
416             {
417                 File targetFile = new File( targetPath, filename );
418                 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
419                 {
420                     throw new ArchivaRestServiceException(
421                         "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
422                         Response.Status.BAD_REQUEST.getStatusCode(), null );
423                 }
424                 else
425                 {
426                     copyFile( new File( fileMetadata.getServerFileName() ), targetPath, filename, fixChecksums );
427                     triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
428                     queueRepositoryTask( repository.getId(), targetFile );
429                 }
430             }
431             catch ( IOException ie )
432             {
433                 throw new ArchivaRestServiceException(
434                     "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
435                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
436             }
437
438             if ( generatePom )
439             {
440                 String pomFilename = filename;
441                 if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
442                 {
443                     pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
444                 }
445                 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
446
447                 try
448                 {
449                     File generatedPomFile =
450                         createPom( targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging );
451                     triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
452                     if ( fixChecksums )
453                     {
454                         fixChecksums( generatedPomFile );
455                     }
456                     queueRepositoryTask( repoConfig.getId(), generatedPomFile );
457                 }
458                 catch ( IOException ie )
459                 {
460                     throw new ArchivaRestServiceException(
461                         "Error encountered while writing pom file: " + ie.getMessage(),
462                         Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
463                 }
464             }
465
466             // explicitly update only if metadata-updater consumer is not enabled!
467             if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
468             {
469                 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
470                                        fixChecksums, fileMetadata, groupId, artifactId, version, packaging );
471
472                 if ( VersionUtil.isSnapshot( version ) )
473                 {
474                     updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
475                                            newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
476                                            packaging );
477                 }
478             }
479         }
480         catch ( RepositoryNotFoundException re )
481         {
482             throw new ArchivaRestServiceException( "Target repository cannot be found: " + re.getMessage(),
483                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re );
484         }
485         catch ( RepositoryException rep )
486         {
487             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
488                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
489         }
490         catch ( RepositoryAdminException e )
491         {
492             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
493                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
494         }
495     }
496
497     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
498         throws RepositoryMetadataException
499     {
500         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
501         if ( metadataFile.exists() )
502         {
503             try
504             {
505                 metadata = MavenMetadataReader.read( metadataFile );
506             }
507             catch ( XMLException e )
508             {
509                 throw new RepositoryMetadataException( e.getMessage(), e );
510             }
511         }
512         return metadata;
513     }
514
515     private File createPom( File targetPath, String filename, FileMetadata fileMetadata, String groupId,
516                             String artifactId, String version, String packaging )
517         throws IOException
518     {
519         Model projectModel = new Model();
520         projectModel.setModelVersion( "4.0.0" );
521         projectModel.setGroupId( groupId );
522         projectModel.setArtifactId( artifactId );
523         projectModel.setVersion( version );
524         projectModel.setPackaging( packaging );
525
526         File pomFile = new File( targetPath, filename );
527         MavenXpp3Writer writer = new MavenXpp3Writer();
528         FileWriter w = new FileWriter( pomFile );
529         try
530         {
531             writer.write( w, projectModel );
532         }
533         finally
534         {
535             IOUtils.closeQuietly( w );
536         }
537
538         return pomFile;
539     }
540
541     private void fixChecksums( File file )
542     {
543         ChecksummedFile checksum = new ChecksummedFile( file );
544         checksum.fixChecksums( algorithms );
545     }
546
547     private void queueRepositoryTask( String repositoryId, File localFile )
548     {
549         RepositoryTask task = new RepositoryTask();
550         task.setRepositoryId( repositoryId );
551         task.setResourceFile( localFile );
552         task.setUpdateRelatedArtifacts( true );
553         task.setScanAll( false );
554
555         try
556         {
557             scheduler.queueTask( task );
558         }
559         catch ( TaskQueueException e )
560         {
561             log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
562                            + "']." );
563         }
564     }
565
566     private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
567         throws IOException
568     {
569         FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
570         FileInputStream input = new FileInputStream( sourceFile );
571
572         try
573         {
574             IOUtils.copy( input, out );
575         }
576         finally
577         {
578             out.close();
579             input.close();
580         }
581
582         if ( fixChecksums )
583         {
584             fixChecksums( new File( targetPath, targetFilename ) );
585         }
586     }
587
588     /**
589      * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
590      */
591     private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
592                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
593                                         String artifactId, String version, String packaging )
594         throws RepositoryMetadataException
595     {
596         List<String> availableVersions = new ArrayList<String>();
597         String latestVersion = version;
598
599         File projectDir = new File( targetPath ).getParentFile();
600         File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
601
602         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
603
604         if ( projectMetadataFile.exists() )
605         {
606             availableVersions = projectMetadata.getAvailableVersions();
607
608             Collections.sort( availableVersions, VersionComparator.getInstance() );
609
610             if ( !availableVersions.contains( version ) )
611             {
612                 availableVersions.add( version );
613             }
614
615             latestVersion = availableVersions.get( availableVersions.size() - 1 );
616         }
617         else
618         {
619             availableVersions.add( version );
620
621             projectMetadata.setGroupId( groupId );
622             projectMetadata.setArtifactId( artifactId );
623         }
624
625         if ( projectMetadata.getGroupId() == null )
626         {
627             projectMetadata.setGroupId( groupId );
628         }
629
630         if ( projectMetadata.getArtifactId() == null )
631         {
632             projectMetadata.setArtifactId( artifactId );
633         }
634
635         projectMetadata.setLatestVersion( latestVersion );
636         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
637         projectMetadata.setAvailableVersions( availableVersions );
638
639         if ( !VersionUtil.isSnapshot( version ) )
640         {
641             projectMetadata.setReleasedVersion( latestVersion );
642         }
643
644         RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
645
646         if ( fixChecksums )
647         {
648             fixChecksums( projectMetadataFile );
649         }
650     }
651
652     /**
653      * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
654      * if necessary.
655      */
656     private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
657                                         Date lastUpdatedTimestamp, String timestamp, int buildNumber,
658                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
659                                         String artifactId, String version, String packaging )
660         throws RepositoryMetadataException
661     {
662         if ( !metadataFile.exists() )
663         {
664             metadata.setGroupId( groupId );
665             metadata.setArtifactId( artifactId );
666             metadata.setVersion( version );
667         }
668
669         if ( metadata.getSnapshotVersion() == null )
670         {
671             metadata.setSnapshotVersion( new SnapshotVersion() );
672         }
673
674         metadata.getSnapshotVersion().setBuildNumber( buildNumber );
675         metadata.getSnapshotVersion().setTimestamp( timestamp );
676         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
677
678         RepositoryMetadataWriter.write( metadata, metadataFile );
679
680         if ( fixChecksums )
681         {
682             fixChecksums( metadataFile );
683         }
684     }
685
686
687 }