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