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